Java client SDK for the Assinafy Webforms API.
Covers the documented authentication, document, signer, assignment, field definition, webhook, template, tag, and high-level uploadAndRequestSignatures flows.
- Java 17+
- Maven 3.8+ (or Gradle 7+)
<dependency>
<groupId>com.assinafy</groupId>
<artifactId>webforms-java-client-sdk</artifactId>
<version>1.4.0</version>
</dependency>implementation 'com.assinafy:webforms-java-client-sdk:1.4.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"));
// Unauthenticated endpoints such as login and public signer flows
new AssinafyClient(new AssinafyClientOptions());AuthenticationResult session = client.auth.login("user@example.com", "password");
String accessToken = session.getAccessToken();
AuthenticationResult googleSession = client.auth.socialLogin(
new SocialLoginPayload("google", googleToken, true));
// These API-key endpoints require a token-authenticated client.
ApiKeyResponse masked = client.auth.getApiKey();
ApiKeyResponse created = client.auth.createApiKey("password");
client.auth.deleteApiKey();
client.auth.changePassword("user@example.com", "old-password", "new-password");
client.auth.requestPasswordReset("user@example.com");
client.auth.resetPassword("user@example.com", resetToken, "new-password");| 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");
// Document tags
List<Tag> tags = client.documents.listTags(doc.getId());
client.documents.appendTags(doc.getId(), List.of("Urgent"));
client.documents.replaceTags(doc.getId(), List.of("Contracts", "2026-Q1"));
client.documents.detachTag(doc.getId(), tagId);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 signingView = client.signerSelf.getSign(signerAccessCode);
DocumentDetails current = client.signerSelf.getCurrentDocument(signerId, signerAccessCode);
PaginatedResult<DocumentDetails> mine = client.signerSelf.listDocuments(
signerId, signerAccessCode, Map.of("status", "pending_signature"));
byte[] signerCopy = client.signerSelf.downloadDocument(signerId, doc.getId(), "original", 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);PaginatedResult<Tag> tags = client.tags.list(Map.of("search", "contract"));
Tag created = client.tags.create(new CreateTagPayload("Contracts").setColor("ff8800"));
Tag updated = client.tags.update(created.getId(),
new UpdateTagPayload().setName("Sales Contracts").clearColor());
client.tags.delete(updated.getId(), true);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"))
.setStep(1)),
new CreateDocumentFromTemplateOptions()
.setTags(List.of("Generated"))
);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