Java client SDK for the Assinafy Webforms API.
Covers the documented document, signer, assignment, field definition, webhook, template, and high-level uploadAndRequestSignatures flows.
- Java 25+
- Maven 3.8+ (or Gradle 7+)
<dependency>
<groupId>com.assinafy</groupId>
<artifactId>webforms-java-client-sdk</artifactId>
<version>1.3.0</version>
</dependency>implementation 'com.assinafy:webforms-java-client-sdk:1.3.0'See docs/INSTALLATION.md for full setup instructions.
import com.assinafy.sdk.AssinafyClient;
import com.assinafy.sdk.AssinafyClientOptions;
import com.assinafy.sdk.models.*;
import java.io.File;
import java.util.List;
AssinafyClient client = new AssinafyClient(new AssinafyClientOptions()
.setApiKey(System.getenv("ASSINAFY_API_KEY"))
.setAccountId(System.getenv("ASSINAFY_ACCOUNT_ID")));
UploadAndRequestSignaturesResult result = client.uploadAndRequestSignatures(
new UploadAndRequestSignaturesOptions(
new File("contract.pdf"),
List.of(
new UploadAndRequestSignaturesSigner("John Doe", "john@example.com"),
new UploadAndRequestSignaturesSigner("Jane Smith", "jane@example.com")
.setWhatsappPhoneNumber("+5548999990000")
)
).setMessage("Please sign this contract")
);
System.out.println("Document ID: " + result.getDocument().getId());// Preferred: X-Api-Key header
new AssinafyClient(new AssinafyClientOptions()
.setApiKey("k_xxx")
.setAccountId("acc_xxx"));
// Legacy: Authorization: Bearer <token>
new AssinafyClient(new AssinafyClientOptions()
.setToken("jwt_xxx")
.setAccountId("acc_xxx"));| Option | Type | Default | Description |
|---|---|---|---|
apiKey |
String | — | Preferred credential (X-Api-Key header) |
token |
String | — | Legacy access token (Bearer header) |
accountId |
String | — | Default account/workspace ID |
baseUrl |
String | https://api.assinafy.com.br/v1 |
API base URL (sandbox or production) |
timeoutMs |
int | 30000 |
Request timeout in milliseconds |
// Positional factory
AssinafyClient client = AssinafyClient.create("api-key", "account-id",
opts -> opts.setTimeoutMs(60_000));
// From a map (snake_case or camelCase keys)
AssinafyClient client = AssinafyClient.fromConfig(Map.of(
"api_key", System.getenv("ASSINAFY_API_KEY"),
"account_id", System.getenv("ASSINAFY_ACCOUNT_ID")
));// Upload from file
DocumentDetails doc = client.documents.upload(new File("contract.pdf"));
// Upload from bytes
DocumentDetails doc = client.documents.upload(pdfBytes, "contract.pdf");
// List documents
PaginatedResult<DocumentListItem> page = client.documents.list(Map.of("page", "1", "per_page", "20"));
// Get document details
DocumentDetails details = client.documents.details(doc.getId());
// Wait until ready for signing
DocumentDetails ready = client.documents.waitUntilReady(doc.getId());
// Download signed PDF
byte[] pdf = client.documents.download(doc.getId());
// Check signing progress
boolean done = client.documents.isFullySigned(doc.getId());
SigningProgress progress = client.documents.getSigningProgress(doc.getId());
// Delete
client.documents.delete(doc.getId());
// Public (unauthenticated) — minimal info for signer landing pages
DocumentDetails publicInfo = client.documents.getPublic(doc.getId());
client.documents.sendToken(doc.getId(), "signer@example.com", "email");Signer signer = client.signers.create(
new CreateSignerPayload("John Doe", "john@example.com")
.setWhatsappPhoneNumber("+5548999990000")
);
// Idempotent by email — reuses if already exists
Signer existing = client.signers.findByEmail("john@example.com");
PaginatedResult<Signer> list = client.signers.list(Map.of("search", "john"));
client.signers.update(signer.getId(), new UpdateSignerPayload().setFullName("Johnny Doe"));
client.signers.delete(signer.getId());Assignment assignment = client.assignments.create(doc.getId(),
new CreateAssignmentPayload()
.setMethod("virtual")
.setSignerStrings(signer1.getId(), signer2.getId())
.setMessage("Please review and sign")
.setExpiresAt("2024-12-31T23:59:00Z"));
client.assignments.resendNotification(doc.getId(), assignment.getId(), signer1.getId());
client.assignments.resetExpiration(doc.getId(), assignment.getId(), "2025-06-30T00:00:00Z");
client.assignments.estimateResendCost(doc.getId(), assignment.getId(), signer1.getId());
client.assignments.whatsappNotifications(doc.getId(), assignment.getId());Endpoints authorised via a short-lived signer-access-code. These are typically called from a
signer landing page rather than from the account-holder's server.
// Fetch the assignment the signer is being asked to complete
Assignment a = client.assignments.get(doc.getId(), assignmentId, signerAccessCode);
// Submit collect-method field values
client.assignments.sign(doc.getId(), assignmentId, signerAccessCode, List.of(
Map.of(
"itemId", "item-1",
"fieldId", "field-1",
"pageId", "page-1",
"value", "John Doe"
)
));
// Decline the assignment
client.assignments.decline(doc.getId(), assignmentId, signerAccessCode, "Not happy with clause 3");// Profile and terms
Signer self = client.signerSelf.getSelf(signerAccessCode);
client.signerSelf.acceptTerms(signerAccessCode);
// Email/WhatsApp verification flow
client.signerSelf.verifyEmail("123456", signerAccessCode);
client.signerSelf.confirmSignerData(doc.getId(), signerAccessCode,
new ConfirmSignerDataPayload().setEmail("a@b.com").setHasAcceptedTerms(true));
// Signature image upload (image type auto-detected as PNG or JPEG)
client.signerSelf.uploadSignature(signerAccessCode, signatureBytes, "signature");
byte[] saved = client.signerSelf.downloadSignature(signerAccessCode, "signature");
// Multi-document signer flows
DocumentDetails current = client.signerSelf.getCurrentDocument(signerId, signerAccessCode);
PaginatedResult<DocumentDetails> mine = client.signerSelf.listDocuments(signerId, signerAccessCode);
client.signerSelf.signMultiple(signerAccessCode, List.of(doc1.getId(), doc2.getId()));
client.signerSelf.declineMultiple(signerAccessCode, List.of(doc1.getId()), "Not interested");WebhookSubscription sub = client.webhooks.register(
new RegisterWebhookPayload("https://example.com/webhooks", "admin@example.com")
.setEvents(List.of("document_ready", "signer_signed_document"))
);
client.webhooks.getSubscription();
client.webhooks.inactivate();
client.webhooks.listEventTypes();
client.webhooks.listDispatches();
client.webhooks.retryDispatch(dispatchId);FieldDefinition field = client.fields.create(new CreateFieldPayload("text", "Reference")
.setRequired(true));
PaginatedResult<FieldDefinition> fields = client.fields.list(
Map.of("include_standard", "true"));
FieldValidationResult validation = client.fields.validate(field.getId(), "ABC-123");
List<FieldTypeInfo> fieldTypes = client.fields.listTypes();PaginatedResult<TemplateListItem> templates = client.templates.list(Map.of("search", "NDA"));
TemplateDetails template = client.templates.get(templateId);
// Create a document from a template
DocumentDetails doc = client.documents.createFromTemplate(
templateId,
List.of(new TemplateSigner(template.getRoles().get(0).getId(), signerId)
.setVerificationMethod("Email")
.setNotificationMethods(List.of("Email")))
);import com.assinafy.sdk.exceptions.*;
try {
client.documents.upload(new File("contract.pdf"));
} catch (ValidationException e) {
System.err.println("Validation: " + e.getMessage() + " " + e.getErrors());
} catch (ApiException e) {
System.err.println("API error " + e.getStatusCode() + ": " + e.getMessage());
} catch (NetworkException e) {
System.err.println("Network: " + e.getMessage());
} catch (AssinafyException e) {
System.err.println("SDK error: " + e.getMessage());
}# Run tests in Docker (recommended)
docker compose run --rm test
# Or run locally with Maven (requires Java 17+)
mvn testMIT