MCP Server for the Assinafy digital signature API. A digital signature platform for Brazil.
Assinafy MCP — Client Reference
A hosted Model Context Protocol Streamable HTTP server for system-to-system
integrations with the Assinafy electronic-signature
platform. The MCP server is a thin, multi-tenant proxy in front of the public
Assinafy REST API (https://api.assinafy.com.br/v1). Every request carries the
caller's API key and account ID; no per-tenant state is stored on the MCP
server itself.
- Endpoint:
https://mcp.assinafy.com.br/mcp - Transport: MCP Streamable HTTP (stateless)
- Protocol version:
2025-11-25 - Auth: per-request HTTPS headers (or per-call
_meta/arguments.auth)
Endpoint methods
The /mcp endpoint accepts two HTTP methods:
| Method | Purpose |
|---|---|
| GET /mcp | Returns a small JSON manifest: server name, version, MCP protocol version, transport, statelessness, and the full list of registered tools (name, title, description, annotations). Useful for capability discovery, browser smoke tests, and uptime probes. |
| POST /mcp | The JSON-RPC entry point for all MCP operations (initialize, tools/list, tools/call, etc.). |
GET /mcp sample:
curl -sS https://mcp.assinafy.com.br/mcp
{
"name": "assinafy-mcp-server",
"version": "0.1.0",
"protocol": "2025-11-25",
"transport": "streamable-http",
"stateless": true,
"status": "ok",
"tools": [
{
"name": "assinafy_list_documents",
"title": "List Documents",
"description": "List documents in an Assinafy workspace with optional pagination and search.",
"annotations": { "readOnlyHint": true, "openWorldHint": true, "title": "List Documents" }
}
// ... 39 more
]
}
The server runs in stateless mode: there is no initialize handshake to
persist, no Mcp-Session-Id to track, and GET /mcp does not open an SSE
stream — clients fire each tools/call as a self-contained POST with the
required headers.
Required headers
Every POST must include the following headers:
| Header | Required | Notes |
|---|---|---|
| Content-Type: application/json | yes | JSON-RPC 2.0 payload. |
| Accept: application/json, text/event-stream | yes | MCP returns each response as a single SSE message event over text/event-stream. |
| MCP-Protocol-Version: 2025-11-25 | yes | Required by the MCP spec on every request to a Streamable HTTP server. |
| X-Api-Key | yes | Your Assinafy API key. Matches the official Assinafy REST API auth header. |
| X-Assinafy-Account-Id | yes | Your workspace (account) ID. |
| X-Assinafy-Webhook-Secret | conditional | Only required for assinafy_verify_webhook_signature, and only when secret is not passed inline as a tool argument. |
Bearer-token authentication is not supported.
The public mcp.assinafy.com.br host sits behind Cloudflare; clients without
a recognisable User-Agent header may be challenged. Standard SDKs and curl
send one by default — urllib-style minimal clients should set one explicitly.
Per-call credentials (no HTTP headers)
Clients that cannot attach custom headers (most browser embeds, some hosted
chat platforms) can supply the same three credentials per tools/call. The
server checks, in order: HTTP headers → _meta → arguments.auth →
arguments.assinafy → arguments.credentials.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "assinafy_list_documents",
"_meta": {
"api_key": "<ASSINAFY_API_KEY>",
"account_id": "<ASSINAFY_ACCOUNT_ID>"
},
"arguments": {}
}
}
Recognised keys (snake_case or camelCase): api_key / apiKey / x_api_key,
account_id / accountId, webhook_secret / webhookSecret. Any tool that
accepts an explicit account_id argument uses that value over the
header/_meta value for the single call.
Calling tools
Every operation flows through standard JSON-RPC tools/call. The HTTP
response body is one SSE frame containing the JSON-RPC result.
curl -sS -X POST https://mcp.assinafy.com.br/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2025-11-25' \
-H "X-Api-Key: $ASSINAFY_API_KEY" \
-H "X-Assinafy-Account-Id: $ASSINAFY_ACCOUNT_ID" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "assinafy_list_documents",
"arguments": { "page": 1, "per_page": 20 }
}
}'
Raw response:
event: message
data: {"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"<JSON>"}],"structuredContent":{...}}}
For object-returning tools the result has both:
result.content[0].text— the JSON payload as a string.result.structuredContent— the same payload as a JSON object.
For tools that return a bare array (e.g. assinafy_get_document_activities)
the MCP SDK only populates result.content[0].text; clients should parse it
with JSON.parse when they need the array. Plain-text results
(delete confirmations, etc.) are returned only as content[0].text.
Failed tool calls return result.isError: true with a human-readable message
in result.content[0].text:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"isError": true,
"content": [{ "type": "text", "text": "API error 400: ..." }]
}
}
The example payloads in the per-tool reference below show the
structuredContent object (or content[0].text for plain-text / array
results). The wrapping envelope is omitted for brevity.
Important: file upload requires server-side filesystem access
assinafy_upload_document reads the PDF directly from the MCP server's
local filesystem using the supplied file_path. This works for self-hosted
deployments (you control the path), but on the public hosted endpoint at
https://mcp.assinafy.com.br/mcp a remote client cannot place a file where
the server can read it.
Public hosted clients have two options:
- Upload via the Assinafy REST API directly (
POST /v1/accounts/{account_id}/documents) and then use the MCP tools (assinafy_get_document,assinafy_create_assignment, …) to drive the rest of the workflow. - Self-host this MCP server alongside whatever ingestion pipeline produces the PDF, so the server-side filesystem path is meaningful.
Every other tool works end-to-end against the public endpoint.
Document lifecycle quick reference
| Status | Meaning |
|---|---|
| uploading | File still being received. |
| uploaded | File received, awaiting metadata extraction. |
| metadata_processing | Backend extracting fields/pages. |
| metadata_ready | Ready for signing setup. |
| pending_signature | Assignment created; waiting on signers. |
| expired | Assignment expired without completion. |
| certificating | Final signing artifact is being generated. |
| certificated | Fully signed; signed PDF + certificate page available. |
| rejected_by_signer | A signer rejected the document. |
| rejected_by_user | The sender cancelled the request. |
| failed | Processing failed. |
assinafy_wait_document_ready returns when the document reaches any of
metadata_ready, pending_signature, or certificated.
Tool reference
All 40 tools, organized by resource. Each entry lists arguments (verified
against the input schema in tools/*.go) and the response shape observed
against the live REST API. Where the underlying API enum is case-sensitive
this is called out — Assinafy's API rejects "email" and accepts "Email".
Documents
assinafy_upload_document
Upload a PDF (max 25 MB) by server-side filesystem path. See the upload note above; only practical for self-hosted MCP deployments.
| Argument | Type | Required | Description |
|---|---|---|---|
| file_path | string | yes | Absolute path on the MCP server's filesystem. |
| account_id | string | no | Override the account ID for this call. |
| metadata | object | no | Arbitrary JSON metadata to attach to the document. |
Response (structuredContent):
{
"resource": "document",
"id": "2222bbbb2222bbbb2222bbbb2222",
"account_id": "aaaa0000aaaa0000aaaa0000",
"name": "sample_contract.pdf",
"status": "uploaded",
"artifacts": {
"original": "https://api.assinafy.com.br/v1/documents/2222bbbb2222bbbb2222bbbb2222/download/original"
},
"pages": [],
"created_at": "2026-05-11T23:25:38Z",
"updated_at": "2026-05-11T23:25:38Z",
"is_closed": false
}
Immediately after upload, status is usually uploaded or
metadata_processing and pages is empty. Call assinafy_wait_document_ready
to block until the backend finishes extracting page metadata.
assinafy_list_documents
| Argument | Type | Required | Description |
|---|---|---|---|
| page | int | no | 1-based page number. |
| per_page | int | no | Results per page (max 100). |
| search | string | no | Filter by document name. |
| sort | string | no | Sort field; prefix - for descending (e.g. -created_at). |
| account_id | string | no | Override account ID. |
Response:
{
"data": [
{
"id": "1111aaaa1111aaaa1111aaaa111",
"account_id": "aaaa0000aaaa0000aaaa0000",
"name": "Sample Agreement.pdf",
"status": "certificated",
"is_closed": true,
"created_at": "2025-03-13T14:24:20Z",
"updated_at": "2025-03-13T14:26:51Z"
}
],
"meta": { "current_page": 1, "last_page": 2, "per_page": 3, "total": 4 }
}
assinafy_get_document
| Argument | Type | Required |
|---|---|---|
| document_id | string | yes |
Response (abridged — assignment.items is included when an assignment exists
and contains the full field-placement data the signing UI uses):
{
"resource": "document",
"id": "1111aaaa1111aaaa1111aaaa111",
"account_id": "aaaa0000aaaa0000aaaa0000",
"name": "Sample Agreement.pdf",
"status": "certificated",
"is_closed": true,
"signing_url": "https://app.assinafy.com.br/sign/1111aaaa1111aaaa1111aaaa111",
"artifacts": {
"original": "https://api.assinafy.com.br/v1/documents/.../download/original",
"thumbnail": "https://api.assinafy.com.br/v1/documents/.../thumbnail",
"certificated": "https://api.assinafy.com.br/v1/documents/.../download/certificated",
"certificate-page": "https://api.assinafy.com.br/v1/documents/.../download/certificate-page",
"bundle": "https://api.assinafy.com.br/v1/documents/.../download/bundle"
},
"assignment": {
"id": "3333cccc3333cccc3333cccc333",
"sender_email": "sender@example.com",
"method": "collect",
"expires_at": null,
"message": null,
"signers": [
{ "id": "4444dddd4444dddd4444dddd444", "full_name": "...", "email": "...", "has_accepted_terms": true }
],
"copy_receivers": [],
"items": [ /* per-page field placements with signer + display_settings */ ],
"summary": {
"signer_count": 1,
"completed_count": 1,
"signers": [ { "id": "...", "full_name": "...", "email": "...", "completed": true } ]
},
"signing_urls": [
{ "signer_id": "4444dddd4444dddd4444dddd444", "url": "https://app.assinafy.com.br/sign/...?email=..." }
]
},
"created_at": "2025-03-13T14:24:20Z",
"updated_at": "2025-03-13T14:26:51Z"
}
The assignment.artifacts URLs follow the document's lifecycle: certificated
/ certificate-page / bundle only appear once the document reaches
certificated.
assinafy_delete_document
Deletes the document (and any active assignment) in one call.
| Argument | Type | Required |
|---|---|---|
| document_id | string | yes |
Response (content[0].text):
Document deleted successfully
assinafy_get_document_activities
Chronological event log. Returns a bare JSON array in content[0].text
(no structuredContent).
| Argument | Type | Required |
|---|---|---|
| document_id | string | yes |
Response (one entry per event; field shapes shown):
[
{
"id": 40549,
"event": "document_ready",
"message": "Documento pronto.",
"origin": null,
"payload": [],
"created_at": "2025-03-13T14:26:51Z"
},
{
"id": 40548,
"event": "signer_signed_document",
"message": "Signatário Jane Q. Sampleton assinou o documento.",
"origin": {
"ip": "203.0.113.1",
"user-agent": "Mozilla/5.0 ..."
},
"payload": {
"signer_full_name": "Jane Q. Sampleton"
},
"created_at": "2025-03-13T14:26:46Z"
}
]
origin is null for system events and an object ({ip, user-agent}) for
signer-driven events. payload is [] when empty and a map when populated.
The MCP server forwards these fields as raw JSON without coercion.
assinafy_wait_document_ready
Polls the document until its status reaches metadata_ready,
pending_signature, or certificated. The polling happens on the MCP server
side — clients see one HTTP response when the document is ready (or when
max_wait_secs elapses).
| Argument | Type | Required | Description |
|---|---|---|---|
| document_id | string | yes | |
| max_wait_secs | int | no | Max seconds to wait (default 30). |
| poll_secs | int | no | Polling interval (default 2). |
Response shape: same as assinafy_get_document.
assinafy_verify_document
Verify a signed document by its Assinafy signature hash. This is not a SHA-1 of the file bytes — it is the per-document hash that Assinafy generates at signing time and renders on the certificate page. Clients usually obtain it from a printed/exported certificate.
| Argument | Type | Required |
|---|---|---|
| hash | string | yes |
Response (when the hash is unknown):
{
"hash": "deadbeef...",
"is_valid": false,
"message": "Documento não assinado ou não encontrado.",
"id": null,
"status": null,
"completed_at": null,
"completed_count": null,
"page_count": null,
"signer_count": null,
"verified_at": "2026-05-11T23:23:48Z"
}
Valid hashes populate id, status, signer_count, completed_count,
completed_at, and page_count. The boolean field is is_valid, not valid.
assinafy_get_signing_progress
| Argument | Type | Required |
|---|---|---|
| document_id | string | yes |
Response:
{ "signed": 1, "total": 1, "pending": 0, "percentage": 100 }
percentage is a number; integer values are returned without a decimal point.
assinafy_create_document_from_template
Create a document from a saved template, mapping signers to template roles.
| Argument | Type | Required | Description |
|---|---|---|---|
| template_id | string | yes | |
| signers | array | yes | [{role_id, id, verification_method?, notification_methods?}]. |
| name | string | no | Custom name for the resulting document. |
| message | string | no | Signing invitation message. |
| expires_at | string | no | ISO 8601 assignment expiry. |
| account_id | string | no | Override account ID. |
verification_method and notification_methods[] values are case-sensitive
and must use the upstream API spelling — see "Enum values" below. Response
shape matches assinafy_get_document.
assinafy_estimate_document_from_template_cost
Estimate the credit cost before committing. Same arguments as
assinafy_create_document_from_template minus the optional fields.
| Argument | Type | Required |
|---|---|---|
| template_id | string | yes |
| signers | array | yes |
| account_id | string | no |
Response shape: same as assinafy_estimate_assignment_cost (see below).
assinafy_download_document
Download a document artifact as base64.
| Argument | Type | Required | Description |
|---|---|---|---|
| document_id | string | yes | |
| artifact | string | no | original (default) or certificated. |
Response:
{
"document_id": "1111aaaa1111aaaa1111aaaa111",
"artifact": "original",
"base64": "JVBERi0xLjQK..."
}
The base64 decodes to the raw PDF bytes (%PDF magic at offset 0).
assinafy_download_signed_document
Convenience wrapper around assinafy_download_document with artifact: "certificated". Errors if the document is not yet certificated.
| Argument | Type | Required |
|---|---|---|
| document_id | string | yes |
Response shape: same as assinafy_download_document.
assinafy_is_fully_signed
| Argument | Type | Required |
|---|---|---|
| document_id | string | yes |
Response:
{ "fully_signed": true }
Signers
assinafy_create_signer
Idempotent by email. If the email is already registered, the existing signer is returned (other fields are not overwritten).
| Argument | Type | Required | Description |
|---|---|---|---|
| full_name | string | yes | |
| email | string | yes | |
| whatsapp_phone_number | string | no | E.164 format. |
| cpf | string | no | Brazilian tax ID. Non-digits are stripped automatically. |
| metadata | object | no | |
| account_id | string | no | |
Response:
{
"id": "5555eeee5555eeee5555eeee5555",
"full_name": "Test Signer",
"email": "test-signer@example.com",
"has_accepted_terms": false
}
has_accepted_terms flips to true once the signer interacts with their
first signing request. cpf, whatsapp_phone_number, and metadata are
omitted from the response when unset.
assinafy_get_signer
| Argument | Type | Required |
|---|---|---|
| signer_id | string | yes |
| account_id | string | no |
Response shape: same as assinafy_create_signer.
assinafy_list_signers
| Argument | Type | Required |
|---|---|---|
| page | int | no |
| per_page | int | no |
| search | string | no |
| account_id | string | no |
Response:
{
"data": [
{ "id": "bbbb0000bbbb0000bbbb0000", "full_name": "Jane Sampleton", "email": "sender@example.com", "has_accepted_terms": true }
],
"meta": { "current_page": 1, "last_page": 1, "per_page": 5, "total": 3 }
}
assinafy_update_signer
Update a signer's contact details. Fails if the signer has active assignments.
| Argument | Type | Required |
|---|---|---|
| signer_id | string | yes |
| full_name, email, whatsapp_phone_number, cpf | string | at least one |
| account_id | string | no |
Response shape: same as assinafy_create_signer.
assinafy_delete_signer
| Argument | Type | Required |
|---|---|---|
| signer_id | string | yes |
| account_id | string | no |
Response (content[0].text):
Signer deleted successfully
assinafy_find_signer_by_email
| Argument | Type | Required |
|---|---|---|
| email | string | yes |
| account_id | string | no |
Returns the signer object (same shape as assinafy_create_signer) when a
match exists. When no match exists the result is the JSON literal null
(content[0].text == "null", no structuredContent).
Assignments
Enum values (read first)
The Assinafy API rejects the lowercase forms that look idiomatic from JavaScript / Python. Use the upstream spelling exactly:
| Field | Accepted values |
|---|---|
| signers[].verification_method | Email, Whatsapp |
| signers[].notification_methods | ["Email"], ["Whatsapp"], or both |
| method (top-level) | virtual, collect |
If you pass "email" instead of "Email" you will get
API error 400: Método de verificação inválido. Pairing
verification_method: "Email" with an empty notification_methods yields
API error 400: O método de verificação de e-mail requer o método de notificação de e-mail.
assinafy_create_assignment
Create a signing assignment and notify signers.
| Argument | Type | Required | Description |
|---|---|---|---|
| document_id | string | yes | |
| signers | array | yes | [{id, verification_method?, notification_methods?}]. |
| method | string | no | virtual (default) or collect. |
| message | string | no | Invitation message shown to signers. |
| expires_at | string | no | ISO 8601. |
| copy_receivers | array | no | Signer IDs that receive a copy without signing. |
Response (structuredContent) — for a single-signer virtual assignment:
{
"id": "6666ffff6666ffff6666ffff6666",
"method": "virtual",
"sender_email": "sender@example.com",
"message": "Demo signing request",
"signers": [
{ "id": "5555eeee5555eeee5555eeee5555", "full_name": "Test Signer", "email": "...", "has_accepted_terms": false }
],
"items": [
{
"id": "7777eeee7777eeee7777eeee7777",
"completed": false,
"field": { "id": "...", "name": "Virtual", "type": "virtual", "is_active": true, "is_required": false, "is_visible": true },
"display_settings": [],
"page": null,
"signer": { "id": "...", "full_name": "...", "email": "..." },
"value": null
}
],
"summary": {
"signer_count": 1,
"completed_count": 0,
"signers": [ { "id": "...", "full_name": "...", "email": "...", "completed": false } ]
},
"signing_urls": [
{ "signer_id": "5555eeee5555eeee5555eeee5555", "url": "https://app.assinafy.com.br/sign/<doc>?email=..." }
]
}
Notes:
signing_urlsis an array of{signer_id, url}objects, not a map.itemsenumerates per-page signature placements. Forvirtualassignments these are single virtual fields; forcollectthey includedisplay_settingswith pixel coordinates and the originatingpagereference.assignment.expires_atmay be returned asnull.
assinafy_estimate_assignment_cost
Estimate the credit cost before creating an assignment. Same signers /
method rules as assinafy_create_assignment (you can pass signers with
just verification_method and notification_methods, no id, when scoping
out a hypothetical assignment).
| Argument | Type | Required |
|---|---|---|
| document_id | string | yes |
| signers | array | yes |
| method | string | no |
Response:
{
"breakdown": [],
"credits": 0,
"credit_balance": 0,
"documents": 1,
"document_balance": 100,
"extra_document_cost": 0,
"needs_extra_document": false,
"has_sufficient_resources": true,
"total_credits": 0
}
breakdown populates when the assignment consumes credits (e.g. WhatsApp
notifications); documents / document_balance track the document budget;
has_sufficient_resources is the single boolean to gate the create call on.
assinafy_reset_assignment_expiration
| Argument | Type | Required |
|---|---|---|
| document_id | string | yes |
| assignment_id | string | yes |
| expires_at | string (ISO 8601) | yes |
Response: the updated assignment object (same shape as
assinafy_create_assignment).
assinafy_resend_notification
Resend the signing invitation to a single signer.
| Argument | Type | Required |
|---|---|---|
| document_id | string | yes |
| assignment_id | string | yes |
| signer_id | string | yes |
Response:
{ "is_sent": true, "document_id": "doc_...", "signer_id": "sig_..." }
assinafy_estimate_resend_cost
Different response shape from assinafy_estimate_assignment_cost — this one
is in terms of credits only, not document budget.
| Argument | Type | Required |
|---|---|---|
| document_id | string | yes |
| assignment_id | string | yes |
| signer_id | string | yes |
Response:
{
"breakdown": [
{ "code": "NotificationEmailResend", "name": "Email Notification Resend", "cost": 0 }
],
"credit_balance": 0,
"has_sufficient_credits": true,
"total": 0
}
assinafy_cancel_signature_request
Cancel an in-progress signature request for a document. The underlying
endpoint is not part of the public Assinafy Swagger; in practice it returns
API error 404 on documents in some states (e.g. already-cancelled,
already-certificated). For routine cleanup, prefer
assinafy_delete_document — it removes the document and any active
assignment in one call regardless of state.
| Argument | Type | Required |
|---|---|---|
| document_id | string | yes |
| reason | string | yes |
| account_id | string | no |
Successful response:
{ "id": "doc_...", "status": "rejected_by_user", "decline_reason": "..." }
Webhooks
assinafy_register_webhook
Register (or replace) the workspace's webhook subscription.
| Argument | Type | Required | Description |
|---|---|---|---|
| url | string | yes | HTTPS endpoint receiving events. |
| email | string | yes | Contact email for delivery failures. |
| events | array | no | Event types to subscribe to; defaults to the full standard set. |
| is_active | bool | no | Default true. |
| account_id | string | no | |
Response:
{
"url": "https://hooks.example.com/assinafy",
"email": "ops@example.com",
"events": ["document_ready", "signer_signed_document"],
"is_active": true,
"updated_at": "2026-04-11T14:22:26Z"
}
The workspace can have only one subscription. Registering replaces the
existing one. id and created_at are not part of the standard response.
assinafy_get_webhook
| Argument | Type | Required |
|---|---|---|
| account_id | string | no |
A workspace that has never registered a webhook returns an empty-shape object,
not null:
{ "url": "", "email": "", "events": [], "is_active": true, "updated_at": "..." }
Clients should treat url == "" as "no webhook configured."
assinafy_delete_webhook
| Argument | Type | Required |
|---|---|---|
| account_id | string | no |
Response (content[0].text):
Webhook subscription deleted
assinafy_inactivate_webhook
Disable the subscription without deleting it.
| Argument | Type | Required |
|---|---|---|
| account_id | string | no |
Response: the subscription object with is_active: false.
assinafy_list_webhook_event_types
No arguments. Returns a bare array (in content[0].text).
[
{ "id": "document_uploaded", "description": "Triggered when the User has uploaded a Document" },
{ "id": "document_metadata_ready", "description": "Triggered when the document is ready to be prepared. ..." },
{ "id": "document_prepared", "description": "Triggered when the User as subject prepares a Document." },
{ "id": "assignment_created", "description": "Triggered when the User created an assignment ..." },
{ "id": "signature_requested", "description": "Triggered when the User requested signature of a Document" },
{ "id": "document_ready", "description": "Triggered when the last Signer ... signs the Document ..." },
{ "id": "signer_created", "description": "Triggered when the User created a Signer" },
{ "id": "signer_email_verified", "description": "Triggered when Signer's email has been verified ..." },
{ "id": "signer_whatsapp_verified", "description": "Triggered when Signer's WhatsApp ... has been verified ..." },
{ "id": "signer_signed_document", "description": "Triggered when Signer completed signing" },
{ "id": "signer_rejected_document", "description": "Triggered when Signer rejected the document" }
// see live response for the authoritative current list
]
This is the canonical list — prefer it over hand-maintained constants.
assinafy_list_webhook_dispatches
| Argument | Type | Required | Description |
|---|---|---|---|
| event | string | no | Filter by event type. |
| delivered | bool | no | Filter by delivery status. |
| page, per_page | int | no | Pagination. |
| account_id | string | no | |
Response:
{
"data": [
{
"id": "wd_...",
"event": "signer_signed_document",
"activity_id": 42,
"endpoint": "https://hooks.example.com/assinafy",
"delivered": true,
"http_status": 200,
"created_at": 1715184000
}
],
"meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
created_at on dispatch records is a Unix epoch integer (seconds), not an
ISO 8601 string. endpoint, http_status, response_body, and error may
be omitted (null) when the delivery has not yet been attempted.
assinafy_retry_webhook_dispatch
| Argument | Type | Required |
|---|---|---|
| dispatch_id | string | yes |
| account_id | string | no |
Response: the updated dispatch record (same shape as the items in
assinafy_list_webhook_dispatches).
assinafy_verify_webhook_signature
Validate that a received webhook body matches its X-Assinafy-Signature
header using HMAC-SHA256. The signature is the raw hex digest, not a
sha256=<hex> prefixed value. Pass the secret in any of three ways:
arguments.secret(per-call).X-Assinafy-Webhook-SecretHTTPS header._meta.webhook_secret/arguments.auth.webhook_secret.
| Argument | Type | Required | Description |
|---|---|---|---|
| payload | string | yes | Raw webhook request body, byte-for-byte. |
| signature | string | yes | Value of X-Assinafy-Signature (hex digest, no prefix). |
| secret | string | no | Webhook secret; falls back to per-request creds. |
Valid signature:
{
"valid": true,
"event_type": "signer_signed_document",
"event_data": { "document_id": "doc_abc", "signer_id": "sig_xyz" }
}
Invalid signature (or missing secret):
{ "valid": false }
The HMAC comparison is timing-safe. event_data is taken from the envelope's
data field (or object, whichever is present).
Workspaces
assinafy_create_workspace
| Argument | Type | Required |
|---|---|---|
| name | string | yes |
| primary_color | string (hex) | no |
| secondary_color | string (hex) | no |
Response shape: WorkspaceResponse — {id, name, primary_color?, secondary_color?, created_at}.
assinafy_list_workspaces
No arguments. Returns every workspace the API key can access, wrapped in {data: [...]} (the API response is a paginated list).
{
"data": [
{
"id": "aaaa0000aaaa0000aaaa0000",
"name": "Demo Workspace",
"is_delete_allowed": true,
"roles": ["owner"],
"created_at": "2023-07-18T19:27:29Z"
}
]
}
assinafy_get_workspace
| Argument | Type | Required |
|---|---|---|
| account_id | string | yes |
Response:
{
"id": "aaaa0000aaaa0000aaaa0000",
"name": "Demo Workspace",
"created_at": "2023-07-18T19:27:29Z"
}
primary_color / secondary_color are present only when the workspace has
them configured.
assinafy_update_workspace
| Argument | Type | Required | Description |
|---|---|---|---|
| account_id | string | yes | Workspace to update. |
| name | string | no | New display name. |
| primary_color | string | null | no | New color or null to clear. |
| secondary_color | string | null | no | New color or null to clear. |
Response shape: WorkspaceResponse.
assinafy_delete_workspace
| Argument | Type | Required |
|---|---|---|
| account_id | string | yes |
Response (content[0].text):
Workspace deleted successfully
Templates
assinafy_list_templates
| Argument | Type | Required |
|---|---|---|
| page, per_page | int | no |
| search | string | no |
| account_id | string | no |
Response:
{
"data": [
{
"id": "tpl_...",
"name": "Service Agreement",
"status": "ready",
"account_id": "aaaa0000aaaa0000aaaa0000",
"created_at": "2026-04-01T10:00:00Z",
"updated_at": "2026-04-02T11:30:00Z"
}
],
"meta": { "current_page": 1, "last_page": 0, "per_page": 20, "total": 0 }
}
Empty workspaces return data: [] with total: 0.
assinafy_get_template
| Argument | Type | Required |
|---|---|---|
| template_id | string | yes |
| account_id | string | no |
Response:
{
"id": "tpl_...",
"name": "Service Agreement",
"status": "ready",
"account_id": "aaaa0000aaaa0000aaaa0000",
"roles": [
{ "id": "role_buyer", "name": "Buyer" },
{ "id": "role_seller", "name": "Seller" }
],
"created_at": "2026-04-01T10:00:00Z",
"updated_at": "2026-04-02T11:30:00Z"
}
Unknown IDs return API error 404: Template não encontrado.
Errors
Tool-level failures (validation, upstream 4xx/5xx, network) return
result.isError: true with the message in result.content[0].text:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"isError": true,
"content": [{ "type": "text", "text": "API error 400: ..." }]
}
}
Common categories:
- Validation errors. Missing required arguments, missing credentials, or
rejected enum values (
Método de verificação inválidoon lowercaseverification_method). - Upstream API errors. The text is prefixed with
API error <code>:followed by the upstream Portuguese-language message (e.g.API error 401: ...,API error 404: Página não encontrada.). - Network errors. Transport-level failures reaching the upstream Assinafy
API. Surface as
network error: ....
Protocol-level failures (malformed JSON-RPC, unknown methods) are returned
through standard JSON-RPC error objects (response.error) rather than the
tool envelope.
Webhook event types (full list)
Subscribe to any subset via assinafy_register_webhook. The authoritative
list is whatever assinafy_list_webhook_event_types returns — the upstream
catalog evolves.
Documents:
document_uploaded,document_metadata_ready,document_prepared,document_ready,document_processing_failed
Assignments / signing:
assignment_created,signature_requested
Signers:
signer_created,signer_email_verified,signer_whatsapp_verified,signer_data_confirmed,signer_viewed_document,signer_signed_document,signer_rejected_document,user_rejected_document
Templates:
template_created,template_processed,template_processing_failed