Zignature API

Programmatically create templates, send documents for signing, and manage your entire document workflow. The API uses JSON for request and response bodies and standard HTTP methods.

Base URL
https://app.zignature.io/api
Authentication
X-Auth-Token
API key in request header
Format
JSON
Request & response bodies
API Documents
$0.20
Per document signed via API

Authentication

All API requests require authentication via the X-Auth-Token header. You can find your API token in Settings → API within your Zignature dashboard.

Your API token carries full account privileges. Keep it secret — never expose it in client-side code, public repositories, or browser requests. Use environment variables and server-side calls only.

Production
Live API token
Documents count toward billing at $0.20/doc
Sandbox
Test API token
Free, unlimited. Documents watermarked TEST

Errors

The API uses standard HTTP status codes to indicate the result of a request. Codes in the 2xx range indicate success. Codes in the 4xx range indicate a client error. Codes in the 5xx range indicate a server error.

StatusMeaningDescription
200OKRequest succeeded
201CreatedResource successfully created
401UnauthorizedMissing or invalid X-Auth-Token header
403ForbiddenAuthenticated but not authorized to access this resource
404Not FoundThe requested resource does not exist
422UnprocessableValidation failed — check the error field in the response body
429Too Many RequestsRate limit exceeded — wait before retrying
500Server ErrorAn unexpected error occurred on our end

Error responses return a JSON body with an error field describing the issue:

OAuth 2.0

For third-party integrations, Zignature supports the standard OAuth 2.0 Authorization Code flow. This allows your application to access Zignature on behalf of a user without handling their credentials directly.

Endpoints

EndpointMethodDescription
/oauth/authorizeGETDisplay consent screen to the user
/oauth/tokenPOSTExchange authorization code or refresh token for an access token
/oauth/revokePOSTRevoke an access or refresh token
/oauth/registerPOSTDynamic client registration — register a public PKCE client without credentials (RFC 7591)
/.well-known/oauth-authorization-serverGETOAuth server metadata — endpoints, capabilities, supported scopes (RFC 8414)
/.well-known/oauth-protected-resourceGETMCP resource metadata — points clients to the auth server (RFC 9728)

Authorization Flow

1
Register an OAuth App

Create an application in Developer Portal → OAuth Apps. You’ll receive a client_id and client_secret.

2
Redirect to Authorize

Send the user to /oauth/authorize with your client_id, redirect_uri, response_type=code, and requested scope.

3
User Grants Access

The user sees a consent screen listing the requested scopes and approves your app. Zignature redirects back to your redirect_uri with a temporary code.

4
Exchange Code for Token

POST to /oauth/token with the code, client_id, client_secret, and grant_type=authorization_code. You’ll receive an access_token (valid 2 hours) and refresh_token.

5
Make API Calls

Use the access token as a Bearer token: Authorization: Bearer YOUR_ACCESS_TOKEN. When expired, use the refresh token to get a new one.

Available Scopes

ScopeDescription
templates:readView templates and their fields
templates:writeCreate, edit, and archive templates
submissions:readView submissions, documents, and signer status
submissions:writeSend documents, create submissions, and manage signers
webhooks:readView webhook endpoints and delivery logs
webhooks:manageCreate, update, and delete webhook endpoints
account:readView account info and team members
account:manageManage account settings, users, and billing

Token Details

ParameterValue
Access token lifetime2 hours (7200 seconds)
Authorization code lifetime10 minutes (600 seconds)
Refresh tokenReturned with every token exchange; use to obtain a new access token
Client authenticationConfidential apps: request body or HTTP Basic Auth (client_id:client_secret). Public PKCE clients: client_id + code_verifier only — no secret required.
GET /oauth/authorize Authorization request

Redirect the user to this endpoint to begin the authorization flow. Displays a consent screen listing the requested scopes. On approval, redirects back to redirect_uri with a temporary authorization code.

ParameterTypeDescription
client_id requiredstringYour OAuth application’s client ID
redirect_uri requiredstringFor registered apps: must match a pre-registered URI. For PKCE public clients registered via /oauth/register: any valid HTTPS URI is accepted.
response_type requiredstringMust be code
scopestringSpace-separated list of scopes (e.g. templates:read submissions:write)
statestringOpaque value for CSRF protection; returned unchanged in the callback
code_challengestringPKCE challenge. Required for public clients (those registered via /oauth/register). Base64url(SHA-256(code_verifier)).
code_challenge_methodstringMust be S256 (recommended) or plain. Defaults to S256.
✓ 302 Redirect
Location: https://yourapp.com/callback?code=abc123def456&state=random_csrf_token
POST /oauth/token Exchange code or refresh token

Exchange an authorization code for an access token, or use a refresh token to obtain a new access token. Client authentication is required via body params or HTTP Basic Auth.

ParameterTypeDescription
grant_type requiredstringauthorization_code or refresh_token
codestringThe authorization code (required when grant_type=authorization_code)
refresh_tokenstringThe refresh token (required when grant_type=refresh_token)
client_id requiredstringYour OAuth application’s client ID
client_secretstringYour client secret. Required for confidential apps. Omit for public PKCE clients (registered via /oauth/register) — use code_verifier instead.
redirect_uristringRequired when grant_type=authorization_code; must match the URI used in the authorize step
code_verifierstringPKCE verifier. Required when a code_challenge was used in the authorize step. A random 43–128 character string.
✓ 200 OK
{
  "access_token": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
  "token_type": "Bearer",
  "expires_in": 7200,
  "refresh_token": "f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5",
  "scope": "templates:read submissions:write",
  "created_at": 1740000000
}
POST /oauth/revoke Revoke a token

Invalidate an access token or refresh token. The token is immediately revoked and can no longer be used. Per RFC 7009, this endpoint always returns 200 even if the token was already revoked or not found.

ParameterTypeDescription
token requiredstringThe access token or refresh token to revoke
client_id requiredstringYour OAuth application’s client ID
client_secret requiredstringYour OAuth application’s client secret
✓ 200 OK
{}
POST /oauth/register Dynamic client registration (RFC 7591)

Register a new OAuth application programmatically without needing a Zignature account. Used by AI platforms (e.g. claude.ai) that need a client_id before starting the OAuth flow. Registration is idempotent — the same client_name + redirect_uris combination always returns the same client_id. No authentication required. Accepts JSON body.

ParameterTypeDescription
client_namestringHuman-readable app name. Defaults to MCP Client.
redirect_uris requiredstring[]Array of valid HTTPS redirect URIs (or http://localhost). At least one required.
✓ 201 Created
{
  "client_id": "mcp_06f9696fbe8d17928971711f0416",
  "client_name": "claude.ai",
  "redirect_uris": ["https://claude.ai/api/mcp/auth_callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "none",
  "scope": "read write"
}

PKCE (Public Clients)

For clients that cannot safely store a client_secret (browser apps, mobile apps, AI platforms), Zignature supports the OAuth 2.0 PKCE extension (RFC 7636). These public clients use a one-time code_verifier instead of a secret.

  1. Register via POST /oauth/register → receive a client_id (no secret).
  2. Generate a cryptographically random 43–128 character code_verifier.
  3. Compute code_challenge = BASE64URL(SHA256(code_verifier)).
  4. Redirect to /oauth/authorize with code_challenge and code_challenge_method=S256.
  5. Exchange the auth code at /oauth/token with code_verifier — no client_secret required.

Discovery Endpoints

OAuth-aware clients (including MCP hosts) auto-discover all endpoints and capabilities without manual configuration. Both endpoints are public and require no authentication.

URLDescription
GET /.well-known/oauth-authorization-serverFull server metadata: all endpoint URLs, supported grant types, scopes, and PKCE methods (RFC 8414)
GET /.well-known/oauth-protected-resourceMCP resource metadata pointing to the auth server (RFC 9728). Also returned in the WWW-Authenticate header of any unauthenticated POST /mcp response.

Account

Retrieve information about the currently authenticated API user and account.

GET /api/user Get current user

Returns the currently authenticated user's profile and account details. Useful for verifying API token validity and retrieving account configuration.

✓ 200 OK
{
  "id": 6,
  "email": "erik@zignature.io",
  "first_name": "Erik",
  "last_name": "Admin",
  "role": "admin",
  "account_id": 6,
  "account_name": "Zignature",
  "created_at": "2026-01-15T08:00:00Z",
  "updated_at": "2026-02-19T12:30:00Z"
}

Quick Start

Send your first signature request in under 60 seconds. Just three steps: get your API key, create a template in the dashboard, then call the API.

1
Get your API key

Go to Settings → API in your dashboard and copy your token.

2
Create a template

Upload a PDF or build from scratch in the template editor. Note the template ID.

3
Send for signing

Make a POST request to /api/submissions with the template ID and submitter emails. See the code example on the right.

Embedding

Embed Zignature signing forms directly into your application. Provide a seamless in-app signing experience without redirecting users away from your product.

Full documentation: Signing Form Component · Form Builder Component

your-app.com/contracts/sign

Form Embed

Generate an embed for a specific signer. Each embed is tied to one submission and one recipient. Create a submission via POST /api/submissions with "send_email": false, then embed the returned embed_src URL. Each submission counts as one API send. Best for contracts, proposals, and one-to-one signing.

Embed Events

Listen for signing events from the embedded form using window.addEventListener('message', ...). Events include:

EventDescription
completedSubmitter finished signing the document
declinedSubmitter declined to sign
loadedSigning form fully loaded in iframe

Submissions

Signature requests are initiated with the Submissions API. Submissions can contain one or multiple submitters. Creating a submission sends the document for signing.

GET /api/submissions List all submissions
ParameterTypeDescription
template_idIntegerFilter by template
statusStringFilter: pending, completed, declined, expired
qStringSearch by name, email, or phone
slugStringFilter by unique submission slug
template_folderStringFilter by folder name
archivedBooleanReturn only archived submissions when true
limitIntegerResults per page (default: 10, max: 100)
afterIntegerCursor ID — returns submissions with ID greater than this value
beforeIntegerCursor ID — returns submissions with ID less than this value
✓ 200 OK
{
  "data": [{
    "id": 42,
    "source": "api",
    "status": "completed",
    "created_at": "2026-02-19T10:00:00Z",
    "updated_at": "2026-02-19T15:30:00Z",
    "archived_at": null,
    "submitters": [{
      "id": 101,
      "email": "signer@example.com",
      "status": "completed",
      "role": "First Party"
    }],
    "template": {
      "id": 1000,
      "name": "Service Agreement"
    }
  }],
  "pagination": {
    "count": 10,
    "next": 43,
    "prev": 32
  }
}
GET /api/submissions/{id} Get a submission
ParameterTypeDescription
idrequiredIntegerThe submission ID

Returns the submission with full submitter details, document URLs, field values, and audit events. Document URLs are signed and expire after the configured period.

✓ 200 OK
{
  "id": 42,
  "source": "api",
  "status": "completed",
  "created_at": "2026-02-19T10:00:00Z",
  "updated_at": "2026-02-19T15:30:00Z",
  "submitters": [{
    "id": 101,
    "email": "signer@example.com",
    "name": "John Doe",
    "role": "First Party",
    "status": "completed",
    "completed_at": "2026-02-19T15:30:00Z",
    "embed_src": "https://app.zignature.io/s/abc123",
    "values": [
      {"field": "Full Name", "value": "John Doe"},
      {"field": "Signature", "value": "https://..."}
    ],
    "documents": [{
      "name": "contract.pdf",
      "url": "https://..."
    }]
  }],
  "combined_document_url": "https://app.zignature.io/blobs/...",
  "audit_log_url": "https://app.zignature.io/blobs/...",
  "template": {
    "id": 1000,
    "name": "Service Agreement"
  }
}

combined_document_url is only populated once all submitters have completed. audit_log_url is available once the audit trail has been generated.

GET /api/submissions/{id}/documents Download signed documents
ParameterTypeDescription
idrequiredIntegerThe submission ID

Add ?merge=true to combine all documents into a single PDF. If the submission is not yet completed, returns a preview with current field values filled in.

✓ 200 OK
{
  "id": 42,
  "documents": [{
    "name": "contract.pdf",
    "url": "https://app.zignature.io/blobs/..."
  }]
}
POST /api/submissions Create a submission
ParameterTypeDescription
template_idrequiredIntegerTemplate to send for signing
submittersrequiredArrayList of submitters with email, role, name, phone
send_emailBooleanSend invitation emails (default: true). Set false for embedding.
send_smsBooleanSend via SMS (default: false)
orderStringpreserved (sequential) or random (parallel)
completed_redirect_urlStringRedirect URL after completion
expire_atStringExpiration date (ISO 8601)
messageObjectCustom email subject and body
bcc_completedStringBCC email for signed documents
reply_toStringReply-to email for invitation messages
external_idStringYour application-specific unique key
sender_nameStringDisplay name shown in the "From" field of invitation emails (e.g. River Realty). Overrides your account name for this submission. Use brand_profile_id for full white-label control including logo.
brand_profile_idIntegerID of a Brand Profile to apply to invitation emails. Sets the sender name and logo for this submission. Takes precedence over sender_name.

Submitter Properties

PropertyTypeDescription
emailStringSubmitter email address
roleStringRole name (e.g. "First Party")
nameStringSubmitter full name
phoneStringPhone number (E.164 format)
valuesObjectPre-filled field values
metadataObjectCustom key-value metadata
completedBooleanAuto-sign this submitter immediately — no email sent, no signing link required. Use this for the "concierge" / host-signs-on-behalf pattern: set completed: true (alias: concierge: true) on the platform-side signer and pass their field values; only the remaining signers receive email links. form.completed and (when all done) submission.completed webhooks fire normally.
fieldsArrayPer-field config: name, default_value, readonly, required
✓ 200 OK
[{
  "id": 1,
  "submission_id": 42,
  "email": "signer@example.com",
  "role": "First Party",
  "status": "sent",
  "slug": "abc123",
  "embed_src": "https://app.zignature.io/s/abc123",
  "preferences": {}
}]
POST /api/submissions/init Initialize a submission

Creates a submission and returns a structured response with the submission ID and submitter details including embed_src URLs. Accepts the same parameters as POST /api/submissions. Ideal for embedded signing flows where you need the submission ID and embed URLs immediately.

ParameterTypeDescription
template_idrequiredIntegerTemplate to send for signing
submittersrequiredArrayList of submitters with email, name, role, phone
send_emailBooleanSend invitation emails (default: true). Set false for embedded signing.
send_smsBooleanSend via SMS (default: false)
orderStringpreserved (sequential) or random (parallel)
completed_redirect_urlStringRedirect URL after completion
expire_atStringExpiration date (ISO 8601)
messageObjectCustom email subject and body
✓ 200 OK
{
  "id": 42,
  "submitters": [{
    "id": 101,
    "slug": "abc123",
    "email": "signer@example.com",
    "embed_src": "https://app.zignature.io/s/abc123",
    "role": "First Party",
    "status": "sent"
  }]
}
POST /api/submissions/emails Send by email (simplified)

Simplified endpoint for sending signature requests via email. Pass submitter email addresses directly.

✓ 200 OK
[{
  "id": 102,
  "submission_id": 43,
  "email": "jane@company.com",
  "status": "sent",
  "slug": "def456",
  "embed_src": "https://app.zignature.io/s/def456"
}]
DELETE /api/submissions/{id} Archive a submission
ParameterTypeDescription
idrequiredIntegerThe submission ID (in URL path)

Archives the submission. Archived submissions can be restored from the dashboard. Returns the archived submission object.

✓ 200 OK
{
  "id": 42,
  "status": "pending",
  "archived_at": "2026-02-20T09:00:00Z"
}
GET /api/submissions/{id}/download Download signed PDF

Redirects to the signed combined PDF for a completed submission. Returns 422 if the submission is not yet fully completed by all parties.

ParameterTypeDescription
idrequiredIntegerThe submission ID (in URL path)
✓ 302 Redirect

Redirects to a time-limited signed PDF URL. Follow the redirect to download the file, or use the Location header URL directly.

POST /api/submissions/{id}/remind Send reminder

Re-sends the signature request email to all pending (unsigned) submitters, or to a specific submitter if submitter_id is provided.

ParameterTypeDescription
idrequiredIntegerThe submission ID (in URL path)
submitter_idIntegerOptional submitter ID to remind only that specific signer. Pass in URL path as /api/submissions/{id}/remind/{submitter_id}
✓ 200 OK
{
  "sent": true
}
POST /api/submissions/{id}/embed_token Get embed token

Generates a short-lived embed token for a pending submitter. Use the returned embed_url to embed the signing form in an iframe without requiring the signer to have a Zignature account.

ParameterTypeDescription
idrequiredIntegerThe submission ID (in URL path)
submitter_emailStringEmail of the specific pending submitter to generate the token for. If omitted, uses the first pending submitter.
expires_inIntegerToken TTL in seconds (default: 3600, max: 86400)
✓ 200 OK
{
  "token": "eyJ...",
  "embed_url": "https://app.zignature.io/s/abc123?embedded=true",
  "expires_at": "2026-02-20T10:00:00Z"
}

Notarization

Remote Online Notarization (RON) API. Request a notarization session for a completed submission, track status, resend notary invitations, and manage multi-document bundles. The template must have notarization enabled, and all signers must have completed the document before a session can be created.

GET /api/submissions/{id}/notarization Get notarization session

Retrieve the most recent notarization session for a submission, including status, session URLs, identity verification state, and bundle documents.

ParameterTypeDescription
id requiredintegerSubmission ID
curl
curl -X GET https://app.zignature.io/api/submissions/1000/notarization \
  -H "X-Auth-Token: YOUR_API_TOKEN"
Response 200
{
  "id": 42,
  "status": "pending",
  "notary_email": "notary@example.com",
  "notary_name": "Jane Notary",
  "ron_mode": true,
  "booking_type": "on_demand",
  "notarial_acts_count": 1,
  "persona_status": "pending",
  "identity_verified": false,
  "signing_complete": false,
  "scheduled_at": null,
  "started_at": null,
  "completed_at": null,
  "duration_minutes": null,
  "signer_join_url": "https://app.zignature.io/notary/xyz789/join",
  "daily_recording_url": null,
  "bundle": {
    "total_docs": 1,
    "is_bundle": false,
    "documents": []
  },
  "created_at": "2026-05-21T10:00:00Z",
  "updated_at": "2026-05-21T10:00:00Z"
}
POST /api/submissions/{id}/notarization Request notarization

Create a notarization session for a completed submission. All signers must have already completed the document and the template must have notarization enabled. Sends an invitation email to the notary immediately.

ParameterTypeDescription
id requiredintegerSubmission ID
notary_email requiredstringEmail address of the notary to invite
notary_namestringFull name of the notary. Defaults to the email address if omitted.
curl
curl -X POST https://app.zignature.io/api/submissions/1000/notarization \
  -H "X-Auth-Token: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "notary_email": "notary@example.com",
    "notary_name": "Jane Notary"
  }'
Response 201
{
  "id": 42,
  "status": "pending",
  "notary_email": "notary@example.com",
  "notary_name": "Jane Notary",
  "ron_mode": true,
  "signer_join_url": "https://app.zignature.io/notary/xyz789/join",
  "bundle": { "total_docs": 1, "is_bundle": false, "documents": [] },
  "created_at": "2026-05-21T10:00:00Z",
  "updated_at": "2026-05-21T10:00:00Z"
}
DEL /api/submissions/{id}/notarization Cancel notarization session

Cancel a pending or active notarization session. Completed sessions cannot be cancelled. If a Schedly booking exists it is also cancelled automatically.

ParameterTypeDescription
id requiredintegerSubmission ID
curl
curl -X DELETE https://app.zignature.io/api/submissions/1000/notarization \
  -H "X-Auth-Token: YOUR_API_TOKEN"
Response 200
{
  "ok": true,
  "id": 42,
  "status": "cancelled"
}
POST /api/submissions/{id}/notarization/resend Resend notary invitation

Resend the invitation email to the notary for a pending or active session. Returns an error if the session is completed or cancelled.

ParameterTypeDescription
id requiredintegerSubmission ID
curl
curl -X POST https://app.zignature.io/api/submissions/1000/notarization/resend \
  -H "X-Auth-Token: YOUR_API_TOKEN"
Response 200
{
  "ok": true,
  "notary_email": "notary@example.com"
}
POST /api/submissions/{id}/notarization/bundle Add document to bundle

Add an additional submission to a pending notarization bundle so that multiple documents are notarized together in the same session. The session must be in pending status. Positions are assigned automatically.

ParameterTypeDescription
id requiredintegerPrimary/anchor submission ID
bundle_submission_id requiredintegerSubmission ID to add to the bundle
curl
curl -X POST https://app.zignature.io/api/submissions/1000/notarization/bundle \
  -H "X-Auth-Token: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "bundle_submission_id": 1001 }'
Response 201
{
  "id": 7,
  "submission_id": 1001,
  "title": "Addendum.pdf",
  "position": 1,
  "signers": 2
}
DEL /api/submissions/{id}/notarization/bundle/{bundle_submission_id} Remove document from bundle

Remove a document from a pending notarization bundle. The session must be in pending status. Bundle positions are reordered automatically after removal.

ParameterTypeDescription
id requiredintegerPrimary/anchor submission ID
bundle_submission_id requiredintegerSubmission ID to remove from the bundle
curl
curl -X DELETE https://app.zignature.io/api/submissions/1000/notarization/bundle/1001 \
  -H "X-Auth-Token: YOUR_API_TOKEN"
Response 200
{
  "ok": true
}

Clickwrap

Drop-in I-Agree consent flows for any website or app. Each agreement has a unique public_slug. Every acceptance is recorded with IP address, browser fingerprint, timestamp, and optional server-verified identity — producing court-admissible consent records compliant with ESIGN, UETA, GDPR, and CCPA. Manage agreements and export audit-ready CSVs from Dashboard → Clickwrap.

WIDGET clickwrap-widget.js JS embed widget

Add a <div data-clickwrap="SLUG"> to your page and load the script. The widget auto-renders as a button, checkbox, or scroll-to-accept panel based on the agreement’s Widget Style setting. No API key needed — the slug is public by design. Find your SLUG in Dashboard → Clickwrap → [Agreement] → Embed.

AttributeTypeDescription
data-clickwrap requiredstringYour agreement’s public_slug
data-clickwrap-emailstringPre-fill user email (server-rendered). Use an identity token for tamper-proof binding.
data-clickwrap-namestringPre-fill user display name
data-clickwrap-user-idstringYour internal user ID — stored in the acceptance record
data-clickwrap-tokenstringServer-signed identity token for cryptographically-verified identity. See Identity token.
data-clickwrap-formstringCSS selector of a form to capture fields from (e.g. #signup-form). Automatically detects the nearest parent form if omitted.
data-clickwrap-fieldsstringComma-separated list of form field names to capture. Defaults to all non-sensitive fields. Passwords, tokens, and CVVs are always blocked.
data-clickwrap-on-acceptedstringName of a global JS function to call on acceptance. Receives the full acceptance result object.
Basic embed
<!-- Drop anywhere in your page -->
<div data-clickwrap="your-slug"></div>
<script src="https://app.zignature.io/clickwrap-widget.js" async></script>
Server-rendered identity (Rails / Django / Next.js)
<div data-clickwrap="your-slug"
     data-clickwrap-email="user@example.com"
     data-clickwrap-name="Jane Smith"
     data-clickwrap-user-id="42"></div>
Capture fields from your signup form
<form id="signup-form">
  <input name="email" />
  <input name="company" />
  <input name="plan" />
</form>

<!-- Widget auto-captures email, company, plan on acceptance -->
<div data-clickwrap="your-slug"
     data-clickwrap-form="#signup-form"
     data-clickwrap-fields="email,company,plan"></div>
Tamper-proof identity token (recommended for legal-grade proof)
<!-- Ruby on Rails: generate server-side, render into page -->
<div data-clickwrap="your-slug"
     data-clickwrap-token="<%= ClickwrapAgreement.find_by!(public_slug:'your-slug')
       .generate_identity_token(email: current_user.email,
                                name:  current_user.name,
                                user_id: current_user.id.to_s) %>"></div>
JS callback on acceptance
<div data-clickwrap="your-slug"
     data-clickwrap-on-accepted="onUserAgreed"></div>

<script>
function onUserAgreed(result) {
  // result: { accepted_at, acceptance_id, version, receipt_url, body_hash }
  console.log('Agreed at', result.accepted_at, '— receipt:', result.receipt_url);
}

// Also available as a DOM event:
document.querySelector('[data-clickwrap]')
  .addEventListener('clickwrap:accepted', e => console.log(e.detail));
</script>
POST /cw/{slug}/accept Record acceptance

Submit an acceptance directly — bypassing the iframe widget. Use for server-side consent recording, native mobile apps, or custom UI flows. No API key required. Rate-limited to 10 requests per IP per minute.

ParameterTypeDescription
slug requiredstringAgreement public_slug (URL path segment)
emailstringUser email. Required when the agreement has Require Email enabled. Overridden by a valid identity_token.
identity_tokenstringServer-signed token (see Identity token). When valid, provides cryptographically-verified email/name and sets identity_source to "token_verified".
metadataobjectUp to 20 custom key-value pairs. String, number, or boolean values only. Keys up to 64 chars, values up to 500 chars.
form_fieldsobjectForm field values captured alongside the acceptance (password/token fields are rejected)
fingerprintobjectBrowser fingerprint signals. Collected automatically by the widget; pass manually for native apps.
curl
curl -X POST https://app.zignature.io/cw/your-slug/accept \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "metadata": {
      "plan": "pro",
      "source": "checkout-page",
      "user_id": "42"
    }
  }'
Response 200
{
  "accepted": true,
  "acceptance_id": 1234,
  "agreement_slug": "your-slug",
  "version": "1.0",
  "body_hash": "a3f2b1c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2",
  "identity_source": "client",
  "accepted_at": "2026-05-21T17:00:00Z",
  "receipt_url": "https://app.zignature.io/cw/your-slug/receipt/TOKEN"
}
identity_source values
"client"         — email from params only (no cryptographic verification)
"token_verified" — identity_token present and valid; email/name cryptographically bound
"token_invalid"  — identity_token present but expired or tampered; fell back to params
GET /cw/{slug}/check Check acceptance

Look up whether an email has accepted the agreement. Returns the most recent acceptance and whether it matches the current active version — so you can detect when a user agreed to an outdated version and re-prompt them. No API key required.

ParameterTypeDescription
slug requiredstringAgreement public_slug (URL path segment)
email requiredstringEmail address to look up (query parameter)
curl
curl "https://app.zignature.io/cw/your-slug/check?email=user%40example.com"
Response — accepted, version current
{
  "accepted": true,
  "acceptance_id": 1234,
  "version_agreed": "1.1",
  "current_version": "1.1",
  "version_current": true,
  "accepted_at": "2026-05-21T17:00:00Z",
  "body_hash": "a3f2b1c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2",
  "receipt_url": "https://app.zignature.io/cw/your-slug/receipt/TOKEN"
}
Response — accepted, stale version (re-prompt needed)
{
  "accepted": true,
  "acceptance_id": 1198,
  "version_agreed": "1.0",
  "current_version": "1.1",
  "version_current": false,
  "accepted_at": "2026-04-10T09:15:00Z",
  "body_hash": "oldHash...",
  "receipt_url": "https://app.zignature.io/cw/your-slug/receipt/TOKEN"
}
Response — not accepted
{
  "accepted": false
}
SERVER Identity token Tamper-proof user identity

Generate a server-signed token to bind user identity to a clickwrap widget session. The token is a SHA-256 HMAC payload signed with the agreement’s widget_secret, expiring after 2 hours by default. Passing a valid token sets identity_source: "token_verified" in the acceptance record — providing legal-grade proof that the accepting party is who they claim to be.

⚠ Never generate tokens client-side. The widget_secret must remain on your server. Expose a backend endpoint that returns the token to authenticated users only.

Ruby on Rails
agreement = ClickwrapAgreement.find_by!(public_slug: 'your-slug')

token = agreement.generate_identity_token(
  email:      current_user.email,
  name:       current_user.name,
  user_id:    current_user.id.to_s,
  expires_in: 2.hours   # default; max recommended: 24 hours
)

# In your ERB view:
# <div data-clickwrap="your-slug"
#      data-clickwrap-token="<%= token %>"></div>
Node.js / Python / Other backends
// Expose a lightweight endpoint on YOUR server that calls your Rails app
// or uses the widget_secret directly to sign with HMAC-SHA256.
// The widget_secret is visible in Dashboard → Clickwrap → [Agreement] → Embed.

// Node.js example (using the Rails /api route to generate the token):
app.get('/api/consent-token', requireAuth, async (req, res) => {
  const r = await fetch('https://app.zignature.io/api/clickwrap_agreements/{id}/identity_token', {
    method: 'POST',
    headers: { 'X-Auth-Token': process.env.ZIGNATURE_API_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({ email: req.user.email, name: req.user.name, user_id: req.user.id })
  });
  const { token } = await r.json();
  res.json({ token });
});
WEBHOOK clickwrap.accepted Acceptance notification

Configure a Webhook URL on your agreement (Dashboard → Clickwrap → [Agreement] → Preferences). Zignature sends an HTTP POST within seconds of every acceptance, with up to 3 automatic retries on failure. SSRF-protected: webhook URLs resolving to private IP ranges are silently rejected.

Request headerValue
Content-Typeapplication/json
User-AgentZignature-Clickwrap/1.0
X-Clickwrap-Eventacceptance
Payload
{
  "event": "clickwrap.accepted",
  "agreement": {
    "id": 1,
    "name": "Terms of Service v1.1",
    "slug": "your-slug",
    "version": "1.1"
  },
  "acceptance": {
    "id": 1234,
    "email": "user@example.com",
    "ip_address": "203.0.113.42",
    "agreement_version": "1.1",
    "body_hash": "a3f2b1c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2",
    "accepted_at": "2026-05-21T17:00:00Z",
    "metadata": {
      "plan": "pro",
      "source": "checkout-page",
      "user_id": "42"
    }
  }
}
Node.js webhook handler
app.post('/webhooks/clickwrap', express.json(), async (req, res) => {
  const { event, agreement, acceptance } = req.body;

  if (event === 'clickwrap.accepted') {
    await db.consents.create({
      email:        acceptance.email,
      version:      acceptance.agreement_version,
      bodyHash:     acceptance.body_hash,
      ipAddress:    acceptance.ip_address,
      acceptedAt:   acceptance.accepted_at,
      agreementId:  agreement.id,
      metadata:     acceptance.metadata
    });
  }

  res.status(200).json({ ok: true }); // respond 2xx quickly to avoid retry
});

Templates

Manage reusable document templates. Templates define the structure of your documents including signature fields, text inputs, and form elements.

GET /api/templates List all templates
ParameterTypeDescription
qStringSearch templates by name
folderStringFilter by folder name
archivedBooleanReturn archived templates only
external_idStringFilter by external ID
limitIntegerResults per page (default: 10, max: 100)
afterIntegerCursor ID — returns templates with ID greater than this value
beforeIntegerCursor ID — returns templates with ID less than this value
✓ 200 OK
{
  "data": [{
    "id": 1000,
    "name": "Service Agreement",
    "created_at": "2026-01-10T08:00:00Z",
    "updated_at": "2026-02-15T12:00:00Z",
    "folder_name": "Contracts",
    "fields": [{
      "uuid": "f1a2b3c4-0000-0000-0000-000000000001",
      "name": "Full Name",
      "type": "text",
      "required": true,
      "submitter_uuid": "s1b2c3d4-0000-0000-0000-000000000010"
    }],
    "submitters": [{"name": "First Party", "uuid": "s1b2c3d4-0000-0000-0000-000000000010"}],
    "author": {
      "id": 6,
      "email": "erik@zignature.io"
    }
  }],
  "pagination": {
    "count": 10,
    "next": 1001,
    "prev": 990
  }
}
GET /api/templates/{id} Get template details
ParameterTypeDescription
idrequiredIntegerThe template ID

Returns the full template object including name, fields, schema, documents, submitter roles, and configuration. Document URLs are signed and expire after the configured period.

✓ 200 OK
{
  "id": 1000,
  "name": "Service Agreement",
  "created_at": "2026-01-10T08:00:00Z",
  "updated_at": "2026-02-15T12:00:00Z",
  "folder_name": "Contracts",
  "external_id": null,
  "schema": [{
    "attachment_uuid": "a1b2c3d4",
    "name": "contract.pdf"
  }],
  "fields": [
    {"uuid": "f1a2b3c4-0000-0000-0000-000000000001", "name": "Full Name", "type": "text", "required": true, "submitter_uuid": "a1b2c3d4-0000-0000-0000-000000000010"},
    {"uuid": "f1a2b3c4-0000-0000-0000-000000000002", "name": "Signature", "type": "signature", "required": true, "submitter_uuid": "a1b2c3d4-0000-0000-0000-000000000010"},
    {"uuid": "f1a2b3c4-0000-0000-0000-000000000003", "name": "Date", "type": "date", "required": false, "submitter_uuid": "a1b2c3d4-0000-0000-0000-000000000020"}
  ],
  "submitters": [
    {"name": "Host", "uuid": "a1b2c3d4-0000-0000-0000-000000000010"},
    {"name": "Client", "uuid": "a1b2c3d4-0000-0000-0000-000000000020"}
  ],
  "author": {
    "id": 6,
    "email": "erik@zignature.io"
  },
  "documents": [{
    "name": "contract.pdf",
    "url": "https://app.zignature.io/blobs/..."
  }]
}
PUT /api/templates/{id} Update a template

Update template properties including name, folder, external ID, roles, and field configurations.

ParameterTypeDescription
idrequiredIntegerThe template ID (in URL path)
nameStringUpdated template name
folder_nameStringMove template to this folder
external_idStringYour application-specific unique key
rolesArrayUpdate submitter role names
fieldsArrayUpdate field definitions
✓ 200 OK
{
  "id": 1000,
  "name": "Updated Agreement",
  "updated_at": "2026-02-20T09:00:00Z",
  "folder_name": "Contracts",
  "external_id": "ext-123"
}
POST /api/templates/{id}/clone Clone a template

Creates a full duplicate of the template including all documents, fields, and configuration.

ParameterTypeDescription
idrequiredIntegerThe template ID to clone (in URL path)
nameStringName for the cloned template
folder_nameStringFolder for the cloned template
external_idStringExternal ID for the cloned template
✓ 200 OK
{
  "id": 1001,
  "name": "Service Agreement (Copy)",
  "created_at": "2026-02-20T09:00:00Z",
  "folder_name": "Contracts",
  "fields": [...],
  "submitters": [{"name": "First Party", "uuid": "s1b2c3d4-0000-0000-0000-000000000010"}]
}
POST /api/templates/{id}/submissions Create submission from template

Create a new submission directly from a template. This is a convenience endpoint — equivalent to POST /api/submissions with the template ID in the URL path instead of the request body.

ParameterTypeDescription
idrequiredIntegerThe template ID (in URL path)
submittersrequiredArrayList of submitters with email, name, role, phone
send_emailBooleanSend invitation emails (default: true)
orderStringpreserved or random
✓ 200 OK
[{
  "id": 103,
  "submission_id": 44,
  "email": "signer@example.com",
  "role": "First Party",
  "status": "sent",
  "slug": "ghi789",
  "embed_src": "https://app.zignature.io/s/ghi789"
}]
GET /api/templates/{id}/submissions List template submissions

Retrieve all submissions created from a specific template. Supports pagination.

ParameterTypeDescription
idrequiredIntegerThe template ID (in URL path)
limitIntegerResults per page (default: 10, max: 100)
afterIntegerCursor ID for pagination
beforeIntegerCursor ID for pagination
✓ 200 OK
{
  "data": [{
    "id": 42,
    "source": "api",
    "status": "pending",
    "created_at": "2026-02-19T10:00:00Z",
    "submitters": [{
      "id": 101,
      "email": "signer@example.com",
      "status": "sent"
    }],
    "template": {
      "id": 1000,
      "name": "Service Agreement"
    }
  }],
  "pagination": {
    "count": 5,
    "next": 43,
    "prev": 37
  }
}
PUT /api/templates/{id}/documents Update template documents

Add, replace, or remove documents within an existing template. Useful for updating the PDF/DOCX content while preserving the template's fields and settings.

ParameterTypeDescription
idrequiredIntegerThe template ID (in URL path)
documentsrequiredArrayArray of document objects to add or replace. Each has name, file (base64 or URL), optional position (Integer) for placement order, and optional remove (Boolean) to delete an existing document
mergeBooleanMerge all documents (existing + new) into a single PDF (default: false)
✓ 200 OK
{
  "id": 1000,
  "name": "Service Agreement",
  "updated_at": "2026-02-20T09:00:00Z",
  "documents": [{
    "id": 1,
    "filename": "agreement_v2.pdf"
  }]
}
DELETE /api/templates/{id} Archive a template
ParameterTypeDescription
idrequiredIntegerThe template ID (in URL path)

Archives the template. Archived templates can be restored from the dashboard. Returns the archived template object.

✓ 200 OK
{
  "id": 1000,
  "name": "Service Agreement",
  "archived_at": "2026-02-20T09:00:00Z"
}
POST /api/templates/{id}/editor_session Create editor session

Generates a signed, expiring URL that opens the full drag-and-drop template builder inside an <iframe> — no Zignature login required. Load the editor_url in an iframe inside your own app so customers can configure their document fields without ever leaving your product. Saves post back to your account automatically. Use postMessage events to react to field changes and completion in real time.

ParameterTypeDescription
idrequiredIntegerThe template ID (in URL path)
expires_inIntegerSession TTL in seconds (default: 3600, max: 86400)
allowed_fieldsArray<String>Restrict available field types. Valid values: text, signature, date, number, checkbox, radio, select, cells, initials, image, stamp, phone, payment, file. Omit to allow all.
theme[accent_color]StringHex color for the Done button and accents (default: #4f46e5)
theme[logo_url]StringURL to your logo shown in the editor topbar
theme[button_label]StringLabel for the primary action button (default: Done)
webhook_urlStringURL to receive a POST when the template is saved. Payload includes template_id, field_count, and your metadata.
submitter_nameStringScope saves to a specific submitter role (e.g. "Host"). Must match a submitter name from GET /api/templates/{id}. Other submitters' fields are preserved untouched. The editor UI always shows all roles — scoping is enforced server-side on save only.
metadataObjectArbitrary key/value pairs echoed back in every postMessage event and webhook payload. Useful for correlating sessions with your own records.
✓ 200 OK
{
  "editor_url": "https://app.zignature.io/embed/editor/eyJ...",
  "build_url": "https://app.zignature.io/embed/editor/eyJ...",
  "token": "eyJ...",
  "expires_at": "2026-02-20T11:00:00Z",
  "submitter_name": "Host",
  "template": {
    "id": 1000,
    "name": "Service Agreement",
    "field_count": 3
  },
  "postmessage_events": [
    "editor.ready", "editor.saved", "editor.done",
    "editor.field.added", "editor.field.removed",
    "editor.error", "editor.fields", "editor.navigate"
  ]
}

Both editor_url and build_url contain the same URL — build_url is provided for compatibility. The endpoint is also available as POST /api/templates/{id}/build_url.

postMessage events (fired to parent window)

Event typeWhen fired
editor.readyBuilder fully mounted and interactive
editor.savedAuto-save completed successfully
editor.doneUser clicked the Done button (final save triggered)
editor.field.addedA field was placed on the document
editor.field.removedA field was deleted
editor.errorA save attempt failed
editor.fieldsResponse to editor.command.get_fields
editor.navigateThe builder attempted internal navigation (e.g. after save). Navigation is blocked inside the iframe — handle this event to close or reload the embed if needed. Payload includes url.

Commands (send from parent to iframe)

Command typeEffect
editor.command.saveTrigger an immediate save
editor.command.get_fieldsRequest current fields array (fires editor.fields back)
editor.command.get_templateRequest full template data (fires editor.template back)

Per-submitter scoping

To limit saves to a specific signer role, pass submitter_name matching a role in your template. First, retrieve your template's roles and their UUIDs:

// Get submitter names and UUIDs
const tpl = await fetch('/api/templates/1000', {
  headers: { 'X-Auth-Token': API_KEY }
}).then(r => r.json());

// tpl.submitters → [{ name: "Host", uuid: "abc-123" }, { name: "Guest", uuid: "def-456" }]

// Create a scoped session — only "Host" fields can be modified
const res = await fetch('/api/templates/1000/editor_session', {
  method: 'POST',
  headers: { 'X-Auth-Token': API_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({ submitter_name: 'Host', metadata: { user_id: 'u_789' } })
});
const { editor_url } = await res.json();

The editor UI still displays all submitters' fields for context. Only fields whose submitter_uuid matches the named role are written on save — other roles' fields are untouched.

Example integration

// 1. Create a session (server-side)
const res = await fetch('/api/templates/1000/editor_session', {
  method: 'POST',
  headers: { 'X-Auth-Token': API_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    expires_in: 3600,
    allowed_fields: ['text', 'signature', 'date'],
    theme: { accent_color: '#7c3aed', button_label: 'Save & Close' },
    metadata: { customer_id: 'cust_001' }
  })
});
const { editor_url } = await res.json();

// 2. Embed in an iframe
const iframe = document.createElement('iframe');
iframe.src = editor_url;
iframe.style.cssText = 'width:100%;height:700px;border:none;';
document.getElementById('editor-container').appendChild(iframe);

// 3. Listen for events
window.addEventListener('message', (e) => {
  if (e.data.type === 'editor.done') {
    console.log('Fields saved:', e.data.field_count);
    iframe.remove(); // or close your modal
  }
  if (e.data.type === 'editor.navigate') {
    // Builder attempted navigation — iframe stays put, handle as needed
    iframe.remove();
  }
});
POST /api/templates/{id}/analyze Analyze fields with AI

Uses AI (Claude) to scan the template's documents and return suggested fillable field positions. Returns bounding boxes, types, and confidence scores for each detected field.

ParameterTypeDescription
idrequiredIntegerThe template ID (in URL path)
✓ 200 OK
{
  "suggested_fields": [{
    "type": "signature",
    "name": "Signature",
    "page": 1,
    "x": 0.12,
    "y": 0.74,
    "width": 0.25,
    "height": 0.06,
    "confidence": 0.91
  }, {
    "type": "date",
    "name": "Date",
    "page": 1,
    "x": 0.62,
    "y": 0.74,
    "width": 0.15,
    "height": 0.04,
    "confidence": 0.87
  }]
}
POST /api/templates/{id}/documents Add a document to template

Append a new document to an existing template. To replace or remove existing documents use PUT /api/templates/{id}/documents instead.

ParameterTypeDescription
idrequiredIntegerThe template ID (in URL path)
filerequiredStringBase64-encoded file content or a publicly accessible URL
nameStringDisplay name for the document
positionIntegerZero-based insert position among existing documents
✓ 201 Created — Updated template object (same shape as Create template)
POST /api/templates/{id}/fields Add a field to template

Add a new fillable field to the template. Coordinates are expressed as fractions of the page dimensions (0.0–1.0).

ParameterTypeDescription
idrequiredIntegerThe template ID (in URL path)
typerequiredStringField type: text, signature, date, number, checkbox, radio, select, initials, image, stamp, phone, file, payment, cells
nameStringDisplay name (auto-generated if omitted)
pageIntegerZero-based page index (default: 0)
xFloatHorizontal position as a fraction of page width (default: 0.1)
yFloatVertical position as a fraction of page height (default: 0.1)
widthFloatField width as a fraction of page width
heightFloatField height as a fraction of page height
submitter_uuidStringUUID of the template submitter (role) this field belongs to. Defaults to the first submitter.
requiredBooleanWhether the field must be filled before submission (default: true)
✓ 201 Created
{
  "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "type": "signature",
  "name": "Signature",
  "page": 0,
  "x": 0.12,
  "y": 0.74,
  "width": 0.25,
  "height": 0.06,
  "required": true,
  "submitter_uuid": "d4e5f6a7-b8c9-0123-def0-123456789abc"
}
DELETE /api/templates/{id}/fields/{field_uuid} Remove a field from template
ParameterTypeDescription
idrequiredIntegerThe template ID (in URL path)
field_uuidrequiredStringThe field UUID to remove (in URL path)
✓ 200 OK
{"ok": true}

Submitters

View and manage individual signers within a submission. Each submitter represents a person who needs to sign or fill out parts of the document.

GET /api/submitters List all submitters
ParameterTypeDescription
submission_idIntegerFilter by submission
qStringSearch by name, email, or phone
completed_afterStringFilter submitters completed after this date (ISO 8601)
completed_beforeStringFilter submitters completed before this date (ISO 8601)
external_idStringFilter by external ID
limitIntegerResults per page (default: 10, max: 100)
afterIntegerCursor ID — returns submitters with ID greater than this value
beforeIntegerCursor ID — returns submitters with ID less than this value
✓ 200 OK
{
  "data": [{
    "id": 101,
    "submission_id": 42,
    "email": "signer@example.com",
    "name": "John Doe",
    "role": "First Party",
    "status": "completed",
    "completed_at": "2026-02-19T15:30:00Z",
    "opened_at": "2026-02-19T14:00:00Z",
    "sent_at": "2026-02-19T10:00:00Z"
  }],
  "pagination": {
    "count": 10,
    "next": 102,
    "prev": 91
  }
}
GET /api/submitters/{id} Get submitter details
ParameterTypeDescription
idrequiredIntegerThe submitter ID

Returns the submitter with status, field values, document URLs, metadata, and audit events. Document URLs are signed and expire after the configured period.

✓ 200 OK
{
  "id": 101,
  "submission_id": 42,
  "email": "signer@example.com",
  "name": "John Doe",
  "role": "First Party",
  "slug": "abc123",
  "status": "completed",
  "sent_at": "2026-02-19T10:00:00Z",
  "opened_at": "2026-02-19T14:00:00Z",
  "completed_at": "2026-02-19T15:30:00Z",
  "embed_src": "https://app.zignature.io/s/abc123",
  "values": [
    {"field": "Full Name", "value": "John Doe"},
    {"field": "Signature", "value": "https://..."}
  ],
  "documents": [{
    "name": "contract.pdf",
    "url": "https://app.zignature.io/blobs/..."
  }],
  "metadata": {}
}
PUT /api/submitters/{id} Update a submitter
ParameterTypeDescription
idrequiredIntegerThe submitter ID (in URL path)
nameStringSubmitter full name
emailStringUpdated email address
phoneStringUpdated phone number (E.164 format)
external_idStringYour application-specific unique key
valuesObjectPre-filled field values
metadataObjectCustom key-value metadata
send_emailBooleanRe-send invitation email after update
send_smsBooleanRe-send invitation via SMS after update
completedBooleanMark submitter as completed (auto-sign)
✓ 200 OK
{
  "id": 101,
  "email": "signer@example.com",
  "name": "John Doe",
  "phone": "+15551234567",
  "status": "sent",
  "external_id": "user-456",
  "metadata": {"plan": "enterprise"},
  "updated_at": "2026-02-20T09:00:00Z"
}

Tools & Utilities

Utility endpoints for document operations like merging templates, verifying PDF signatures, and sending documents in bulk.

POST /api/tools/merge Merge multiple PDFs

Merge multiple PDF files into a single PDF document. Accepts base64-encoded PDF files and returns a single merged PDF.

ParameterTypeDescription
filesrequiredArrayArray of base64-encoded PDF files to merge (minimum 2)
✓ 200 OK
{
  "data": "JVBERi0xLjQKMS..."
}
POST /api/tools/verify Verify PDF signature

Verify the digital signature on a signed PDF document. Returns checksum verification against the Zignature database and detailed signature information including signer identity, signing reason, and certificate chain validation.

ParameterTypeDescription
filerequiredStringBase64-encoded PDF file content
✓ 200 OK
{
  "checksum_status": "verified",
  "signatures": [{
    "signer_name": "John Doe",
    "signing_reason": "Document signing",
    "signing_time": "2026-02-19T15:30:00Z",
    "signature_type": "adbe.pkcs7.detached",
    "verification_result": ["The signature is valid."]
  }]
}
POST /api/tools/convert Convert DOCX/HTML to PDF

Convert a DOCX or HTML file to PDF. Returns a signed download URL valid for 1 hour.

ParameterTypeDescription
filerequiredString or FileBase64-encoded DOCX/HTML file content, a publicly accessible URL, or a multipart upload. Supported extensions: .docx, .html
filenameStringRequired when providing a raw base64 string so the converter knows the file type (e.g. document.docx)
✓ 200 OK
{
  "url": "https://app.zignature.io/blobs/...",
  "filename": "document.pdf"
}
POST /api/bulk_send Bulk send to multiple recipients

Send a template to up to 100 recipients in a single API call via CRM integration. Each recipient gets their own independent submission. Optionally resolves CRM field values automatically when provider and record_id are provided per recipient.

ParameterTypeDescription
template_idrequiredIntegerTemplate to send
recipientsrequiredArrayArray of recipient objects, max 100. Each requires email and optionally name, record_id (CRM record for merge fields)
providerStringCRM provider for field value resolution: salesforce, hubspot, pipedrive, zoho_crm
object_typeStringCRM object type (default: Contact)
✓ 200 OK
{
  "total": 3,
  "sent": 2,
  "failed": 1,
  "results": [
    {"email": "alice@example.com", "status": "sent", "submission_id": 45},
    {"email": "bob@example.com", "status": "sent", "submission_id": 46},
    {"email": "bad@", "status": "failed", "error": "Email is required"}
  ]
}
POST /api/submissions/bulk Create multiple submissions

Create up to 100 independent submissions from a single template in one call. Unlike POST /api/bulk_send, this endpoint is not CRM-specific and is the preferred way to programmatically batch-create submissions. Invitation emails are sent automatically after each submission is created.

ParameterTypeDescription
template_idrequiredIntegerTemplate to use for all submissions
submittersrequiredArrayArray of submitter objects (max 100). Each requires email and optionally name, values, metadata, external_id
✓ 201 Created
{
  "submissions": [
    {
      "email": "alice@example.com",
      "status": "sent",
      "submission_id": 45,
      "submitter_id": 101
    },
    {
      "email": "bob@example.com",
      "status": "failed",
      "error": "Email has already been taken"
    }
  ]
}
POST /api/attachments Upload a file

Upload a file (PDF, DOCX, or image) and receive a URL that can be used as a file reference in other API calls such as submission creation.

ParameterTypeDescription
filerequiredFileThe file to upload (multipart/form-data)
nameStringOptional display name for the file
✓ 200 OK
{
  "id": 501,
  "uuid": "f8e7d6c5-b4a3-2019-8765-4321fedcba98",
  "url": "https://app.zignature.io/blobs/...",
  "filename": "contract.pdf",
  "content_type": "application/pdf",
  "byte_size": 245890,
  "created_at": "2026-02-20T09:00:00Z"
}

Events API

Retrieve event logs for form and submission activity. Useful for audit trails, debugging, and monitoring your integration.

GET /api/events/form/{type} List form events

Retrieve form completion events. Returns submitter data with documents and attachments. Paginated by completion timestamp.

ParameterTypeDescription
typepathStringEvent type filter: completed
afterIntegerUnix timestamp — return events after this time
beforeIntegerUnix timestamp — return events before this time
limitIntegerNumber of events to return (default: 10)
✓ 200 OK
{
  "data": [{
    "event_type": "form.completed",
    "timestamp": "2026-02-19T15:30:00Z",
    "data": {
      "id": 101,
      "email": "signer@example.com",
      "submission_id": 42,
      "status": "completed",
      "documents": ["https://app.zignature.io/blobs/..."]
    }
  }],
  "pagination": {
    "count": 1,
    "next": 1740000600,
    "prev": 1740000600
  }
}
GET /api/events/submission/{type} List submission events

Retrieve submission completion events. Only returns submissions where all submitters have completed. Paginated by completion timestamp.

ParameterTypeDescription
typepathStringEvent type filter: completed
afterIntegerUnix timestamp — return events after this time
beforeIntegerUnix timestamp — return events before this time
limitIntegerNumber of events to return (default: 10)
✓ 200 OK
{
  "data": [{
    "event_type": "submission.completed",
    "timestamp": "2026-02-19T15:30:00Z",
    "data": {
      "id": 42,
      "source": "api",
      "template_id": 1000,
      "status": "completed",
      "submitters": [{
        "email": "signer@example.com",
        "status": "completed"
      }]
    }
  }],
  "pagination": {
    "count": 1,
    "next": 1740000600,
    "prev": 1740000600
  }
}

Extension / CRM API

Powers CRM integrations (Salesforce Lightning, HubSpot, Pipedrive, Zoho CRM). Provides CRM context fetching, AI-powered field mapping, document sending, audit trails, signer management, and CRM writeback.

GET /api/extension/context Get CRM record context

Fetches CRM record data including fields, values, and related objects. Supports Salesforce, HubSpot, Pipedrive, and Zoho CRM.

ParameterTypeDescription
providerrequiredStringCRM provider: salesforce, hubspot, pipedrive, zoho_crm
record_idrequiredStringThe CRM record ID
object_typeStringCRM object type (default: Contact)
✓ 200 OK
POST /api/extension/field_mappings AI-powered field mapping

Uses AI heuristics to map CRM record fields to template fields with confidence scores. Supports line items and related records.

ParameterTypeDescription
template_idrequiredIntegerTemplate ID to map fields for
crm_fieldsrequiredObjectCRM field key-value pairs
line_itemsArrayProduct/line item data
related_recordsObjectRelated record data (Account, Contact)
✓ 200 OK
POST /api/extension/send Send document for signature

Creates a submission from a template and sends to recipients. Supports CRM field values, line items, and writeback for edited values.

ParameterTypeDescription
template_idrequiredIntegerTemplate to send
recipientsrequiredArrayList of signers (email, name)
field_valuesObjectPre-filled field values
crm_contextObjectCRM context (provider, record_id, object_type)
✓ 200 OK
GET /api/extension/documents List documents for CRM record

Returns all documents associated with a CRM record including signer status, progress, and CRM context.

✓ 200 OK
GET /api/extension/documents/{id}/audit Get document audit trail

Returns the complete audit trail for a document including sent, viewed, signed, declined, and reassigned events.

✓ 200 OK
POST /api/extension/reassign_submitter Reassign a signer

Reassigns a pending signer to a different person. Marks original as declined/reassigned, sends invitation to new signer.

ParameterTypeDescription
submitter_idrequiredIntegerSubmitter ID to reassign
emailrequiredStringNew signer email
nameStringNew signer name
reasonStringReason for reassignment
✓ 200 OK
POST /api/extension/describe_object Describe CRM object schema

Returns field schema for a CRM object type. Supports custom objects across all 4 CRM providers.

✓ 200 OK
GET /api/extension/documents/{id}/download Get document download URL

Returns a download URL for the signed document PDF.

✓ 200 OK
GET /api/extension/profile Get current user profile

Returns the profile of the authenticated user including account settings, CRM connections, and feature flags relevant to the extension.

✓ 200 OK
{
  "id": 6,
  "email": "user@company.com",
  "first_name": "Erik",
  "last_name": "Hanson",
  "account_id": 1,
  "features": {
    "deal_desk": true,
    "bulk_send": true
  }
}
GET /api/extension/templates List templates for extension

Returns the list of templates available to the authenticated user, optimized for the CRM extension context (includes role names and field summaries).

ParameterTypeDescription
qStringSearch templates by name
✓ 200 OK
[{
  "id": 1000,
  "name": "Service Agreement",
  "submitters": [{"name": "Customer"}],
  "fields": [...]
}]
POST /api/extension/preview Get template preview URL

Generates a preview URL for a template with optional pre-filled field values. Useful for showing signers a read-only preview of the document before sending.

ParameterTypeDescription
template_idrequiredIntegerTemplate ID to preview
field_valuesObjectKey-value pairs of field names and values to pre-fill in the preview
✓ 200 OK
{
  "url": "https://app.zignature.io/templates/1000/preview?token=..."
}
POST /api/extension/suggest_fields AI-suggested CRM fields

Uses AI to analyze a template and suggest which CRM fields should be fetched to populate it. Returns field names ranked by relevance.

ParameterTypeDescription
template_idrequiredIntegerTemplate ID to analyze
object_typeStringCRM object type to suggest fields from (e.g. Contact, Opportunity)
providerStringCRM provider: salesforce, hubspot, pipedrive, zoho_crm
✓ 200 OK
{
  "fields": ["FirstName", "LastName", "Email", "Company"]
}
POST /api/extension/resend_notification Resend signer notification

Re-sends the signature request email to a specific pending submitter.

ParameterTypeDescription
submitter_idrequiredIntegerThe submitter ID to resend the notification to
✓ 200 OK
{"sent": true}
PUT /api/extension/update_submitter Update signer details

Updates the email, name, or phone of a pending submitter without reassigning them. The submitter retains their signing link and position.

ParameterTypeDescription
submitter_idrequiredIntegerThe submitter ID to update
emailStringNew email address
nameStringNew full name
phoneStringNew phone number
✓ 200 OK — Updated submitter object
POST /api/extension/documents/{id}/resend Resend document to all pending signers

Re-sends the signature request email to all pending (unsigned) submitters on a document.

ParameterTypeDescription
idrequiredIntegerThe submission ID (in URL path)
✓ 200 OK
{"sent": true}
POST /api/extension/documents/{id}/void Void a document

Voids a pending submission, cancelling all remaining signing requests and notifying signers. Voided submissions cannot be reopened.

ParameterTypeDescription
idrequiredIntegerThe submission ID (in URL path)
reasonStringOptional reason for voiding shown to signers
✓ 200 OK — Voided submission object
POST /api/extension/writeback_rules Configure CRM writeback rules

Saves CRM writeback rules for a template — defining which signed field values should be written back to which CRM fields upon completion.

ParameterTypeDescription
template_idrequiredIntegerTemplate to configure writeback for
rulesrequiredArrayArray of rule objects. Each has field_name (template field) and crm_field (CRM field key)
providerStringCRM provider the rules apply to
object_typeStringCRM object type to write back to
✓ 200 OK
{
  "template_id": 1000,
  "rules": [{
    "field_name": "Signature Date",
    "crm_field": "Close_Date"
  }],
  "saved": true
}

Brand Profiles

Brand Profiles let you white-label invitation emails on a per-submission basis. Create one profile per client or brand, then pass brand_profile_id when creating a submission. Signers see the client's logo and name — not yours.

GET /api/brand_profiles List all brand profiles
ParameterTypeDescription
limitIntegerResults per page (default: 10, max: 100)
afterIntegerCursor — returns profiles with ID greater than this value
beforeIntegerCursor — returns profiles with ID less than this value
✓ 200 OK
{
  "data": [{
    "id": 7,
    "name": "River Realty",
    "sender_name": "River Realty",
    "reply_to": "contracts@riverrealty.com",
    "logo_url": "https://cdn.riverrealty.com/logo-white.png",
    "created_at": "2026-03-01T09:00:00Z",
    "updated_at": "2026-03-01T09:00:00Z"
  }],
  "pagination": {
    "count": 1,
    "next": 7,
    "prev": 7
  }
}
GET /api/brand_profiles/{id} Get a brand profile
ParameterTypeDescription
idrequiredIntegerThe brand profile ID
✓ 200 OK
{
  "id": 7,
  "name": "River Realty",
  "sender_name": "River Realty",
  "reply_to": "contracts@riverrealty.com",
  "logo_url": "https://cdn.riverrealty.com/logo-white.png",
  "created_at": "2026-03-01T09:00:00Z",
  "updated_at": "2026-03-01T09:00:00Z"
}
POST /api/brand_profiles Create a brand profile
ParameterTypeDescription
namerequiredStringInternal label for this profile (e.g. River Realty)
sender_nameStringName shown in the email "From" field. Defaults to name if omitted.
reply_toStringReply-to email address so signer replies go directly to the client
logo_urlStringPublic URL to the client logo shown at the top of invitation emails. Recommended: 400×104px PNG, white or light-colored on a transparent background.
✓ 201 Created
{
  "id": 7,
  "name": "River Realty",
  "sender_name": "River Realty",
  "reply_to": "contracts@riverrealty.com",
  "logo_url": "https://cdn.riverrealty.com/logo-white.png",
  "created_at": "2026-03-01T09:00:00Z",
  "updated_at": "2026-03-01T09:00:00Z"
}
PUT /api/brand_profiles/{id} Update a brand profile
ParameterTypeDescription
idrequiredIntegerThe brand profile ID
nameStringInternal label
sender_nameStringEmail "From" display name
reply_toStringReply-to email address
logo_urlStringPublic logo URL
✓ 200 OK
{
  "id": 7,
  "name": "River Realty",
  "sender_name": "River Realty",
  "reply_to": "contracts@riverrealty.com",
  "logo_url": "https://cdn.riverrealty.com/logo-white.png",
  "created_at": "2026-03-01T09:00:00Z",
  "updated_at": "2026-05-07T12:00:00Z"
}
DEL /api/brand_profiles/{id} Delete a brand profile
ParameterTypeDescription
idrequiredIntegerThe brand profile ID

Deletes the profile. Existing submissions that referenced this profile are unaffected — emails already sent retain their branding.

✓ 200 OK
{
  "id": 7,
  "name": "River Realty",
  "sender_name": "River Realty",
  "reply_to": "contracts@riverrealty.com",
  "logo_url": "https://cdn.riverrealty.com/logo-white.png",
  "created_at": "2026-03-01T09:00:00Z",
  "updated_at": "2026-03-01T09:00:00Z"
}

Deal Desk API

Enterprise-grade deal approval workflows. Query review status, approve, reject, or send back deals. Includes risk scoring, drift detection, and multi-level approval chains. Requires Enterprise plan.

GET /api/extension/deal_desk/review Get deal review status

Retrieves the current deal desk review for a CRM record including status, risk score, drift analysis, approval chain, and activity timeline.

ParameterTypeDescription
providerrequiredStringCRM provider
record_idrequiredStringCRM record ID
object_typeStringCRM object type
✓ 200 OK
{
  "id": 42,
  "status": "pending",
  "current_level": 1,
  "deal_value": 50000.00,
  "risk_score": 35,
  "drift_detected": false,
  "approvals": [{
    "level": 1,
    "status": "pending",
    "approver_type": "role"
  }]
}
POST /api/extension/deal_desk/review/{id}/approve Approve a deal review

Approves the current pending approval level. Advances to next level or completes the review if all levels approved.

ParameterTypeDescription
commentStringOptional approval comment
✓ 200 OK
POST /api/extension/deal_desk/review/{id}/reject Reject a deal review

Rejects the current pending approval level. Comment is required.

ParameterTypeDescription
commentrequiredStringRejection reason
✓ 200 OK
POST /api/extension/deal_desk/review/{id}/send_back Send back for revision

Sends a deal review back to the requester for changes. Comment is required.

ParameterTypeDescription
commentrequiredStringExplanation of what needs revision
✓ 200 OK

Webhooks

Receive real-time HTTP POST notifications when events occur. Configure webhook URLs and secrets in Settings → Webhooks.

submission.created
New submission was created
submission.completed
All submitters finished signing
submission.expired
Submission expired before completion
submission.archived
Submission was archived
form.viewed
Signing form was opened
form.started
Submitter started filling fields
form.completed
Submitter completed and signed
form.declined
Submitter declined to sign
template.created
New template was created
template.updated
Template was modified

Webhook payloads include the full object data. Verify webhook authenticity using your webhook secret with HMAC-SHA256 signature in the X-Hmac-Sha256 header.

Payload envelope

Every webhook POST has this top-level shape. The data object is the submitter for form.* events, and the submission for submission.* events.

{
  "event_type": "form.completed",
  "timestamp": "2026-05-07T12:00:00Z",
  "data": {
    "id": 101,
    "submission_id": 42,
    "email": "client@example.com",
    "name": "Jane Smith",
    "role": "Client",
    "status": "completed",
    "sent_at": "2026-05-07T10:00:00Z",
    "opened_at": "2026-05-07T11:45:00Z",
    "completed_at": "2026-05-07T12:00:00Z",
    "metadata": { "booking_uid": "bk_001" },
    "values": [
      { "field": "Full Name", "value": "Jane Smith" },
      { "field": "Signature", "value": "https://app.zignature.io/blobs/..." }
    ],
    "documents": [{ "name": "NDA.pdf", "url": "https://app.zignature.io/blobs/..." }],
    "audit_log_url": "https://app.zignature.io/blobs/...",
    "template": { "id": 1000, "name": "Booking NDA", "external_id": null },
    "submission": {
      "id": 42,
      "status": "completed",
      "combined_document_url": "https://app.zignature.io/blobs/...",
      "audit_log_url": "https://app.zignature.io/blobs/...",
      "created_at": "2026-05-07T10:00:00Z"
    }
  }
}

Key fields: data.metadata — your key-value pairs from submission creation.   data.documents[].url — this submitter's signed documents.   data.submission.combined_document_url — merged PDF of all parties (only populated once all sign).   data.submission.status — pending | completed | declined | expired.

SCIM v2 Provisioning

Automate user and group provisioning with the SCIM 2.0 API. Connect your identity provider (Okta, Azure AD, OneLogin, etc.) to automatically sync users and teams with Zignature. Requires Enterprise plan.

Base URL & Authentication

All SCIM endpoints are under /api/scim/v2. Authenticate with a SCIM Bearer token generated in Settings → SCIM Provisioning.

DetailValue
Base URLhttps://app.zignature.io/api/scim/v2
Auth headerAuthorization: Bearer YOUR_SCIM_TOKEN
Content-Typeapplication/scim+json

Discovery Endpoints

EndpointDescription
GET /ServiceProviderConfigReturns supported SCIM features (Patch, Bulk, Filter)
GET /ResourceTypesLists supported resource types: User and Group
GET /SchemasFull JSON schemas for User and Group resources

Users

GET /api/scim/v2/Users List users

Returns a paginated list of provisioned users. Supports SCIM filtering with filter parameter (e.g. userName eq "user@example.com").

ParameterTypeDescription
filterstringSCIM filter expression (e.g. userName eq "user@example.com")
startIndexinteger1-based pagination offset (default: 1)
countintegerNumber of results per page (default: 100)
✓ 200 OK
{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
  "totalResults": 2,
  "startIndex": 1,
  "itemsPerPage": 100,
  "Resources": [{
    "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "userName": "jane@example.com",
    "name": { "givenName": "Jane", "familyName": "Smith" },
    "emails": [{ "value": "jane@example.com", "primary": true }],
    "active": true
  }]
}
GET /api/scim/v2/Users/{id} Get user

Retrieve a single user by their UUID.

✓ 200 OK
{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "userName": "jane@example.com",
  "name": { "givenName": "Jane", "familyName": "Smith" },
  "emails": [{ "value": "jane@example.com", "primary": true }],
  "active": true,
  "meta": {
    "resourceType": "User",
    "created": "2026-01-15T08:00:00Z",
    "lastModified": "2026-02-19T12:30:00Z"
  }
}
POST /api/scim/v2/Users Create user

Provision a new user in the account. If a previously archived user matches the email, they will be reactivated.

ParameterTypeDescription
userName requiredstringUser’s email address
name.givenNamestringFirst name
name.familyNamestringLast name
emailsarrayArray of email objects with value and primary fields
✓ 201 Created
{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "userName": "newuser@example.com",
  "name": { "givenName": "New", "familyName": "User" },
  "emails": [{ "value": "newuser@example.com", "primary": true }],
  "active": true
}
PUT /api/scim/v2/Users/{id} Replace user

Full replacement of a user resource. Setting active: false archives the user.

ParameterTypeDescription
userName requiredstringUser’s email address
name.givenNamestringFirst name
name.familyNamestringLast name
activebooleanSet to false to deactivate/archive
✓ 200 OK
{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "userName": "jane@example.com",
  "active": true
}
PATCH /api/scim/v2/Users/{id} Update user

Partial update using SCIM Patch operations. Supported ops: add, replace.

ParameterTypeDescription
Operations requiredarrayArray of patch operations with op, path, and value
✓ 200 OK
{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "userName": "jane@example.com",
  "active": false
}
DELETE /api/scim/v2/Users/{id} Delete user

Archive (soft-delete) a user. The user can be reactivated by creating a new user with the same email.

✓ 204 No Content

Groups

GET /api/scim/v2/Groups List groups

Returns a paginated list of groups (teams). Supports SCIM filtering with filter parameter.

ParameterTypeDescription
filterstringSCIM filter expression (e.g. displayName eq "Engineering")
startIndexinteger1-based pagination offset (default: 1)
countintegerNumber of results per page (default: 100)
✓ 200 OK
{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
  "totalResults": 1,
  "Resources": [{
    "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
    "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
    "displayName": "Engineering",
    "members": [
      { "value": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "display": "jane@example.com" }
    ]
  }]
}
GET /api/scim/v2/Groups/{id} Get group

Retrieve a single group (team) by UUID, including its member list.

✓ 200 OK
{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
  "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "displayName": "Engineering",
  "members": [
    { "value": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "display": "jane@example.com" }
  ],
  "meta": {
    "resourceType": "Group",
    "created": "2026-01-10T09:00:00Z",
    "lastModified": "2026-02-20T14:00:00Z"
  }
}
POST /api/scim/v2/Groups Create group

Create a new group (team) and optionally assign members by their user UUIDs.

ParameterTypeDescription
displayName requiredstringName of the group/team
membersarrayArray of objects with value (user UUID)
✓ 201 Created
{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
  "id": "d4e5f6a7-b8c9-0123-defa-234567890123",
  "displayName": "Sales",
  "members": []
}
PUT /api/scim/v2/Groups/{id} Replace group

Full replacement of a group resource. Replaces the group name and entire member list.

ParameterTypeDescription
displayName requiredstringGroup name
membersarrayComplete member list (replaces existing)
✓ 200 OK
{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
  "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "displayName": "Engineering",
  "members": [
    { "value": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "display": "jane@example.com" }
  ]
}
PATCH /api/scim/v2/Groups/{id} Update group

Partial update using SCIM Patch operations. Supports add, replace, and remove operations. Use path-based filtering to remove specific members (e.g. members[value eq "uuid"]).

ParameterTypeDescription
Operations requiredarrayArray of patch operations with op, path, and value
✓ 200 OK
{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
  "id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "displayName": "Engineering",
  "members": [
    { "value": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "display": "jane@example.com" },
    { "value": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "display": "newuser@example.com" }
  ]
}
DELETE /api/scim/v2/Groups/{id} Delete group

Archive (soft-delete) a group and remove all member associations.

✓ 204 No Content

SDKs & Libraries

Use the Zignature API with your preferred language. All code examples use standard HTTP libraries — no SDK installation required.

JavaScript
📜TypeScript
🐍Python
🔴Ruby
PHP
Java
🖥C#
🐧Go

MCP Server

Connect AI assistants like Claude, ChatGPT, Gemini, Cursor, and VS Code Copilot to Zignature. Manage templates, send documents, handle contracts, run Deal Desk approvals, manage users and teams — all through natural language.

Endpoint

POST https://app.zignature.io/mcp

Protocol

JSON-RPC 2.0 · MCP version 2025-03-26

Transport

Streamable HTTP (single endpoint)

Tools Available

57 tools across 10 categories — full platform control

MCP Authentication

The MCP server accepts two authentication methods. Use whichever fits your client.

Method 1 — API Token (CLI & desktop tools)

Pass your API token as a request header. Best for Claude Desktop, Cursor, Windsurf, VS Code, and any client where you configure headers manually.

HeaderValueDescription
X-Auth-Token requiredstringYour Zignature API token. Found in Developer Portal → API Keys.
Content-Type requiredstringMust be application/json

Method 2 — OAuth 2.0 Bearer Token (browser-based AI clients)

For clients that initiate OAuth from the browser (e.g. claude.ai Remote MCP). The MCP server returns HTTP 401 with a WWW-Authenticate header pointing to the OAuth discovery endpoint. The client then runs the PKCE flow and sends the resulting Bearer token.

HeaderValueDescription
Authorization requiredstringBearer <access_token> — obtained via the OAuth 2.0 PKCE flow described in the OAuth section.
Content-Type requiredstringMust be application/json

When unauthenticated, the server responds: HTTP 401 WWW-Authenticate: Bearer realm="https://app.zignature.io/mcp", resource_metadata="https://app.zignature.io/.well-known/oauth-protected-resource"

Available Tools

The MCP server exposes 64 tools across 11 categories. AI assistants can manage your entire Zignature account.

Templates (8 tools)

ToolDescriptionKey Parameters
list_templatesList templates with search and folder filteringquery, folder
get_templateGet template details, fields, and rolestemplate_id
create_templateCreate a new template with rolesname
update_templateUpdate name or move to foldertemplate_id
archive_templateArchive a templatetemplate_id
restore_templateRestore an archived templatetemplate_id
clone_templateClone a template with all fieldstemplate_id
suggest_templateFind templates by descriptiondescription

Folders (3 tools)

ToolDescriptionKey Parameters
list_foldersList all template folders
create_folderCreate a new foldername
rename_folderRename an existing folderfolder_id, name

Documents & Signing (9 tools)

ToolDescriptionKey Parameters
send_documentSend document for signaturetemplate_id, submitters
bulk_send_documentSend to up to 100 recipientstemplate_id, recipients
list_documentsList submissions with status filtersstatus, query
get_document_statusDetailed signer progresssubmission_id
void_documentCancel a pending documentsubmission_id
download_documentGet signed PDF download URLssubmission_id
get_audit_trailFull event timeline with IPssubmission_id
send_reminderRemind pending signerssubmission_id
archive_documentArchive a submissionsubmission_id

Users & Teams (7 tools)

ToolDescriptionKey Parameters
list_usersList account usersstatus, role
invite_userInvite a new useremail
update_userUpdate user name or roleuser_id
deactivate_userDeactivate a useruser_id
list_teamsList all teams
create_teamCreate a new teamname
manage_team_membersAdd or remove team membersteam_id, action, user_id

Webhooks (5 tools)

ToolDescriptionKey Parameters
list_webhooksList webhook endpoints
create_webhookCreate a webhookurl
update_webhookUpdate webhook URLwebhook_id, url
delete_webhookDelete a webhookwebhook_id
test_webhookSend test eventwebhook_id

Account, Branding & Billing (4 tools)

ToolDescriptionKey Parameters
get_accountAccount details, branding, subscription
update_accountUpdate name, timezone, localename, timezone
update_brandingChange brand colorprimary_color
get_billingPlan, usage, subscription status

Contracts / CLM (8 tools)

ToolDescriptionKey Parameters
list_contractsList contracts with filtersstatus, counterparty
get_contractFull contract details with parties and versionscontract_id
create_contractCreate a draft contracttitle
update_contractUpdate contract detailscontract_id
transition_contractChange contract statuscontract_id, new_status
delete_contractDelete a contractcontract_id
get_contract_dashboardPipeline stats and trends
promote_submission_to_contractCreate contract from signed docsubmission_id

Deal Desk (6 tools)

ToolDescriptionKey Parameters
get_deal_desk_dashboardPending reviews, approval rates, pipeline
list_deal_desk_reviewsList reviews with filtersstatus, risk_level
get_deal_desk_reviewFull review with approvalsreview_id
action_deal_desk_reviewApprove, reject, or send backreview_id, action
list_deal_desk_policiesList approval policies
get_deal_desk_analyticsApproval rates and trendsperiod

Clause Library (4 tools)

ToolDescriptionKey Parameters
list_clausesList clauses with category/searchcategory, query
create_clauseAdd a clause to the librarytitle, content
update_clauseUpdate an existing clauseclause_id
delete_clauseRemove a clauseclause_id

Other (3 tools)

ToolDescriptionKey Parameters
list_notificationsRecent user notificationsunread_only
get_submission_eventsDetailed event logsubmission_id
search_contactsSearch past recipientsquery

Notarization (7 tools)

ToolDescriptionKey Parameters
request_notarizationRequest a RON session — invites a notary and sends the signer join linksubmission_id, notary_email
get_notarization_statusGet full session status, URLs, and bundle detailssubmission_id
cancel_notarizationCancel a pending or active notarization sessionsubmission_id
resend_notary_invitationResend the notary invitation emailsubmission_id
list_notarization_sessionsList sessions for the account, filterable by statusstatus, limit
add_to_notarization_bundleAdd a document to a pending notarization bundlesubmission_id, bundle_submission_id
remove_from_notarization_bundleRemove a document from a pending notarization bundlesubmission_id, bundle_submission_id

Setup Guides

Add Zignature to your AI assistant with a simple configuration snippet. Replace YOUR_API_TOKEN with your actual API token.

Claude Desktop

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "zignature": {
      "url": "https://app.zignature.io/mcp",
      "headers": {
        "X-Auth-Token": "YOUR_API_TOKEN"
      }
    }
  }
}

Claude Code CLI

Run from your terminal:

claude mcp add zignature \
  --transport http \
  --url https://app.zignature.io/mcp \
  --header "X-Auth-Token: YOUR_API_TOKEN"

Cursor

Add to .cursor/mcp.json in your project:

{
  "mcpServers": {
    "zignature": {
      "url": "https://app.zignature.io/mcp",
      "headers": {
        "X-Auth-Token": "YOUR_API_TOKEN"
      }
    }
  }
}

VS Code (Copilot)

Add to .vscode/mcp.json in your project:

{
  "servers": {
    "zignature": {
      "type": "http",
      "url": "https://app.zignature.io/mcp",
      "headers": {
        "X-Auth-Token": "YOUR_API_TOKEN"
      }
    }
  }
}

claude.ai Web (Remote MCP)

Connect Zignature to claude.ai on the web with one click — no config files or API tokens needed. Claude handles the full OAuth flow automatically.

  1. Go to claude.ai → Settings → Integrations.
  2. Click Add custom integration and paste: https://app.zignature.io/mcp
  3. claude.ai will redirect you to Zignature to log in and approve access.
  4. Once authorised, use natural language: “Send an NDA to alice@example.com”.

Under the hood, claude.ai discovers the OAuth server via /.well-known/oauth-protected-resource, auto-registers as a public PKCE client via POST /oauth/register, and completes a standard OAuth 2.0 authorization code + PKCE flow. No API token or manual configuration required.

Windsurf

Add to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "zignature": {
      "serverUrl": "https://app.zignature.io/mcp",
      "headers": {
        "X-Auth-Token": "YOUR_API_TOKEN"
      }
    }
  }
}

Gemini (Google AI Studio)

In Google AI Studio, go to Tools → Add MCP Server and enter:

URL: https://app.zignature.io/mcp
Header: X-Auth-Token: YOUR_API_TOKEN

Gemini will discover all 57 tools automatically via the MCP protocol.

ChatGPT (Custom GPT Actions)

ChatGPT connects to Zignature through GPT Actions using the REST API with an OpenAPI spec. This lets your Custom GPT list templates, send documents, check statuses, and download signed PDFs.

Setup Steps

  1. Go to chatgpt.com/gpts/editor and create a new GPT.
  2. Click Configure → Create new action.
  3. Click Import from URL and paste: https://app.zignature.io/openapi/chatgpt
  4. Under Authentication, select API Key, set Header to X-Auth-Token, and paste your API token.
  5. Save your GPT and start using it — say “List my templates” or “Send an NDA to alice@example.com”.

OpenAPI Spec URL: https://app.zignature.io/openapi/chatgpt

API Pricing $0.20 per document · Volume discounts from $0.10/doc · Sandbox always free
View Full Pricing →