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.
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.
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.
| Status | Meaning | Description |
|---|---|---|
| 200 | OK | Request succeeded |
| 201 | Created | Resource successfully created |
| 401 | Unauthorized | Missing or invalid X-Auth-Token header |
| 403 | Forbidden | Authenticated but not authorized to access this resource |
| 404 | Not Found | The requested resource does not exist |
| 422 | Unprocessable | Validation failed — check the error field in the response body |
| 429 | Too Many Requests | Rate limit exceeded — wait before retrying |
| 500 | Server Error | An 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
| Endpoint | Method | Description |
|---|---|---|
| /oauth/authorize | GET | Display consent screen to the user |
| /oauth/token | POST | Exchange authorization code or refresh token for an access token |
| /oauth/revoke | POST | Revoke an access or refresh token |
| /oauth/register | POST | Dynamic client registration — register a public PKCE client without credentials (RFC 7591) |
| /.well-known/oauth-authorization-server | GET | OAuth server metadata — endpoints, capabilities, supported scopes (RFC 8414) |
| /.well-known/oauth-protected-resource | GET | MCP resource metadata — points clients to the auth server (RFC 9728) |
Authorization Flow
Create an application in Developer Portal → OAuth Apps. You’ll receive a client_id and client_secret.
Send the user to /oauth/authorize with your client_id, redirect_uri, response_type=code, and requested scope.
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.
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.
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
| Scope | Description |
|---|---|
| templates:read | View templates and their fields |
| templates:write | Create, edit, and archive templates |
| submissions:read | View submissions, documents, and signer status |
| submissions:write | Send documents, create submissions, and manage signers |
| webhooks:read | View webhook endpoints and delivery logs |
| webhooks:manage | Create, update, and delete webhook endpoints |
| account:read | View account info and team members |
| account:manage | Manage account settings, users, and billing |
Token Details
| Parameter | Value |
|---|---|
| Access token lifetime | 2 hours (7200 seconds) |
| Authorization code lifetime | 10 minutes (600 seconds) |
| Refresh token | Returned with every token exchange; use to obtain a new access token |
| Client authentication | Confidential apps: request body or HTTP Basic Auth (client_id:client_secret). Public PKCE clients: client_id + code_verifier only — no secret required. |
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.
| Parameter | Type | Description |
|---|---|---|
| client_id required | string | Your OAuth application’s client ID |
| redirect_uri required | string | For registered apps: must match a pre-registered URI. For PKCE public clients registered via /oauth/register: any valid HTTPS URI is accepted. |
| response_type required | string | Must be code |
| scope | string | Space-separated list of scopes (e.g. templates:read submissions:write) |
| state | string | Opaque value for CSRF protection; returned unchanged in the callback |
| code_challenge | string | PKCE challenge. Required for public clients (those registered via /oauth/register). Base64url(SHA-256(code_verifier)). |
| code_challenge_method | string | Must be S256 (recommended) or plain. Defaults to S256. |
Location: https://yourapp.com/callback?code=abc123def456&state=random_csrf_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.
| Parameter | Type | Description |
|---|---|---|
| grant_type required | string | authorization_code or refresh_token |
| code | string | The authorization code (required when grant_type=authorization_code) |
| refresh_token | string | The refresh token (required when grant_type=refresh_token) |
| client_id required | string | Your OAuth application’s client ID |
| client_secret | string | Your client secret. Required for confidential apps. Omit for public PKCE clients (registered via /oauth/register) — use code_verifier instead. |
| redirect_uri | string | Required when grant_type=authorization_code; must match the URI used in the authorize step |
| code_verifier | string | PKCE verifier. Required when a code_challenge was used in the authorize step. A random 43–128 character string. |
{
"access_token": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"token_type": "Bearer",
"expires_in": 7200,
"refresh_token": "f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5",
"scope": "templates:read submissions:write",
"created_at": 1740000000
}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.
| Parameter | Type | Description |
|---|---|---|
| token required | string | The access token or refresh token to revoke |
| client_id required | string | Your OAuth application’s client ID |
| client_secret required | string | Your OAuth application’s client secret |
{}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.
| Parameter | Type | Description |
|---|---|---|
| client_name | string | Human-readable app name. Defaults to MCP Client. |
| redirect_uris required | string[] | Array of valid HTTPS redirect URIs (or http://localhost). At least one required. |
{
"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.
- Register via
POST /oauth/register→ receive aclient_id(no secret). - Generate a cryptographically random 43–128 character
code_verifier. - Compute
code_challenge = BASE64URL(SHA256(code_verifier)). - Redirect to
/oauth/authorizewithcode_challengeandcode_challenge_method=S256. - Exchange the auth code at
/oauth/tokenwithcode_verifier— noclient_secretrequired.
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.
| URL | Description |
|---|---|
| GET /.well-known/oauth-authorization-server | Full server metadata: all endpoint URLs, supported grant types, scopes, and PKCE methods (RFC 8414) |
| GET /.well-known/oauth-protected-resource | MCP 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.
Returns the currently authenticated user's profile and account details. Useful for verifying API token validity and retrieving account configuration.
{
"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.
Go to Settings → API in your dashboard and copy your token.
Upload a PDF or build from scratch in the template editor. Note the template ID.
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
Embed Events
Listen for signing events from the embedded form using window.addEventListener('message', ...). Events include:
| Event | Description |
|---|---|
| completed | Submitter finished signing the document |
| declined | Submitter declined to sign |
| loaded | Signing 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.
| Parameter | Type | Description |
|---|---|---|
| template_id | Integer | Filter by template |
| status | String | Filter: pending, completed, declined, expired |
| q | String | Search by name, email, or phone |
| slug | String | Filter by unique submission slug |
| template_folder | String | Filter by folder name |
| archived | Boolean | Return only archived submissions when true |
| limit | Integer | Results per page (default: 10, max: 100) |
| after | Integer | Cursor ID — returns submissions with ID greater than this value |
| before | Integer | Cursor ID — returns submissions with ID less than this value |
{
"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
}
}| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The 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.
{
"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.
| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The 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.
{
"id": 42,
"documents": [{
"name": "contract.pdf",
"url": "https://app.zignature.io/blobs/..."
}]
}| Parameter | Type | Description |
|---|---|---|
| template_idrequired | Integer | Template to send for signing |
| submittersrequired | Array | List of submitters with email, role, name, phone |
| send_email | Boolean | Send invitation emails (default: true). Set false for embedding. |
| send_sms | Boolean | Send via SMS (default: false) |
| order | String | preserved (sequential) or random (parallel) |
| completed_redirect_url | String | Redirect URL after completion |
| expire_at | String | Expiration date (ISO 8601) |
| message | Object | Custom email subject and body |
| bcc_completed | String | BCC email for signed documents |
| reply_to | String | Reply-to email for invitation messages |
| external_id | String | Your application-specific unique key |
| sender_name | String | Display 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_id | Integer | ID 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
| Property | Type | Description |
|---|---|---|
| String | Submitter email address | |
| role | String | Role name (e.g. "First Party") |
| name | String | Submitter full name |
| phone | String | Phone number (E.164 format) |
| values | Object | Pre-filled field values |
| metadata | Object | Custom key-value metadata |
| completed | Boolean | Auto-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. |
| fields | Array | Per-field config: name, default_value, readonly, required |
[{
"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": {}
}]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.
| Parameter | Type | Description |
|---|---|---|
| template_idrequired | Integer | Template to send for signing |
| submittersrequired | Array | List of submitters with email, name, role, phone |
| send_email | Boolean | Send invitation emails (default: true). Set false for embedded signing. |
| send_sms | Boolean | Send via SMS (default: false) |
| order | String | preserved (sequential) or random (parallel) |
| completed_redirect_url | String | Redirect URL after completion |
| expire_at | String | Expiration date (ISO 8601) |
| message | Object | Custom email subject and body |
{
"id": 42,
"submitters": [{
"id": 101,
"slug": "abc123",
"email": "signer@example.com",
"embed_src": "https://app.zignature.io/s/abc123",
"role": "First Party",
"status": "sent"
}]
}Simplified endpoint for sending signature requests via email. Pass submitter email addresses directly.
[{
"id": 102,
"submission_id": 43,
"email": "jane@company.com",
"status": "sent",
"slug": "def456",
"embed_src": "https://app.zignature.io/s/def456"
}]| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The submission ID (in URL path) |
Archives the submission. Archived submissions can be restored from the dashboard. Returns the archived submission object.
{
"id": 42,
"status": "pending",
"archived_at": "2026-02-20T09:00:00Z"
}Redirects to the signed combined PDF for a completed submission. Returns 422 if the submission is not yet fully completed by all parties.
| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The submission ID (in URL path) |
Redirects to a time-limited signed PDF URL. Follow the redirect to download the file, or use the Location header URL directly.
Re-sends the signature request email to all pending (unsigned) submitters, or to a specific submitter if submitter_id is provided.
| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The submission ID (in URL path) |
| submitter_id | Integer | Optional submitter ID to remind only that specific signer. Pass in URL path as /api/submissions/{id}/remind/{submitter_id} |
{
"sent": true
}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.
| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The submission ID (in URL path) |
| submitter_email | String | Email of the specific pending submitter to generate the token for. If omitted, uses the first pending submitter. |
| expires_in | Integer | Token TTL in seconds (default: 3600, max: 86400) |
{
"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.
Retrieve the most recent notarization session for a submission, including status, session URLs, identity verification state, and bundle documents.
| Parameter | Type | Description |
|---|---|---|
| id required | integer | Submission ID |
curl -X GET https://app.zignature.io/api/submissions/1000/notarization \ -H "X-Auth-Token: YOUR_API_TOKEN"
{
"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"
}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.
| Parameter | Type | Description |
|---|---|---|
| id required | integer | Submission ID |
| notary_email required | string | Email address of the notary to invite |
| notary_name | string | Full name of the notary. Defaults to the email address if omitted. |
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"
}'{
"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"
}Cancel a pending or active notarization session. Completed sessions cannot be cancelled. If a Schedly booking exists it is also cancelled automatically.
| Parameter | Type | Description |
|---|---|---|
| id required | integer | Submission ID |
curl -X DELETE https://app.zignature.io/api/submissions/1000/notarization \ -H "X-Auth-Token: YOUR_API_TOKEN"
{
"ok": true,
"id": 42,
"status": "cancelled"
}Resend the invitation email to the notary for a pending or active session. Returns an error if the session is completed or cancelled.
| Parameter | Type | Description |
|---|---|---|
| id required | integer | Submission ID |
curl -X POST https://app.zignature.io/api/submissions/1000/notarization/resend \ -H "X-Auth-Token: YOUR_API_TOKEN"
{
"ok": true,
"notary_email": "notary@example.com"
}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.
| Parameter | Type | Description |
|---|---|---|
| id required | integer | Primary/anchor submission ID |
| bundle_submission_id required | integer | Submission ID to add to the bundle |
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 }'{
"id": 7,
"submission_id": 1001,
"title": "Addendum.pdf",
"position": 1,
"signers": 2
}Remove a document from a pending notarization bundle. The session must be in pending status. Bundle positions are reordered automatically after removal.
| Parameter | Type | Description |
|---|---|---|
| id required | integer | Primary/anchor submission ID |
| bundle_submission_id required | integer | Submission ID to remove from the bundle |
curl -X DELETE https://app.zignature.io/api/submissions/1000/notarization/bundle/1001 \ -H "X-Auth-Token: YOUR_API_TOKEN"
{
"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.
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.
| Attribute | Type | Description |
|---|---|---|
| data-clickwrap required | string | Your agreement’s public_slug |
| data-clickwrap-email | string | Pre-fill user email (server-rendered). Use an identity token for tamper-proof binding. |
| data-clickwrap-name | string | Pre-fill user display name |
| data-clickwrap-user-id | string | Your internal user ID — stored in the acceptance record |
| data-clickwrap-token | string | Server-signed identity token for cryptographically-verified identity. See Identity token. |
| data-clickwrap-form | string | CSS selector of a form to capture fields from (e.g. #signup-form). Automatically detects the nearest parent form if omitted. |
| data-clickwrap-fields | string | Comma-separated list of form field names to capture. Defaults to all non-sensitive fields. Passwords, tokens, and CVVs are always blocked. |
| data-clickwrap-on-accepted | string | Name of a global JS function to call on acceptance. Receives the full acceptance result object. |
<!-- Drop anywhere in your page --> <div data-clickwrap="your-slug"></div> <script src="https://app.zignature.io/clickwrap-widget.js" async></script>
<div data-clickwrap="your-slug"
data-clickwrap-email="user@example.com"
data-clickwrap-name="Jane Smith"
data-clickwrap-user-id="42"></div><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><!-- 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><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>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.
| Parameter | Type | Description |
|---|---|---|
| slug required | string | Agreement public_slug (URL path segment) |
| string | User email. Required when the agreement has Require Email enabled. Overridden by a valid identity_token. | |
| identity_token | string | Server-signed token (see Identity token). When valid, provides cryptographically-verified email/name and sets identity_source to "token_verified". |
| metadata | object | Up to 20 custom key-value pairs. String, number, or boolean values only. Keys up to 64 chars, values up to 500 chars. |
| form_fields | object | Form field values captured alongside the acceptance (password/token fields are rejected) |
| fingerprint | object | Browser fingerprint signals. Collected automatically by the widget; pass manually for native apps. |
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"
}
}'{
"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"
}"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
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.
| Parameter | Type | Description |
|---|---|---|
| slug required | string | Agreement public_slug (URL path segment) |
| email required | string | Email address to look up (query parameter) |
curl "https://app.zignature.io/cw/your-slug/check?email=user%40example.com"
{
"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"
}{
"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"
}{
"accepted": false
}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.
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>
// 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 }); });
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 header | Value |
|---|---|
| Content-Type | application/json |
| User-Agent | Zignature-Clickwrap/1.0 |
| X-Clickwrap-Event | acceptance |
{
"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"
}
}
}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.
| Parameter | Type | Description |
|---|---|---|
| q | String | Search templates by name |
| folder | String | Filter by folder name |
| archived | Boolean | Return archived templates only |
| external_id | String | Filter by external ID |
| limit | Integer | Results per page (default: 10, max: 100) |
| after | Integer | Cursor ID — returns templates with ID greater than this value |
| before | Integer | Cursor ID — returns templates with ID less than this value |
{
"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
}
}| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The 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.
{
"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/..."
}]
}Update template properties including name, folder, external ID, roles, and field configurations.
| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The template ID (in URL path) |
| name | String | Updated template name |
| folder_name | String | Move template to this folder |
| external_id | String | Your application-specific unique key |
| roles | Array | Update submitter role names |
| fields | Array | Update field definitions |
{
"id": 1000,
"name": "Updated Agreement",
"updated_at": "2026-02-20T09:00:00Z",
"folder_name": "Contracts",
"external_id": "ext-123"
}Creates a full duplicate of the template including all documents, fields, and configuration.
| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The template ID to clone (in URL path) |
| name | String | Name for the cloned template |
| folder_name | String | Folder for the cloned template |
| external_id | String | External ID for the cloned template |
{
"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"}]
}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.
| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The template ID (in URL path) |
| submittersrequired | Array | List of submitters with email, name, role, phone |
| send_email | Boolean | Send invitation emails (default: true) |
| order | String | preserved or random |
[{
"id": 103,
"submission_id": 44,
"email": "signer@example.com",
"role": "First Party",
"status": "sent",
"slug": "ghi789",
"embed_src": "https://app.zignature.io/s/ghi789"
}]Retrieve all submissions created from a specific template. Supports pagination.
| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The template ID (in URL path) |
| limit | Integer | Results per page (default: 10, max: 100) |
| after | Integer | Cursor ID for pagination |
| before | Integer | Cursor ID for pagination |
{
"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
}
}Add, replace, or remove documents within an existing template. Useful for updating the PDF/DOCX content while preserving the template's fields and settings.
| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The template ID (in URL path) |
| documentsrequired | Array | Array 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 |
| merge | Boolean | Merge all documents (existing + new) into a single PDF (default: false) |
{
"id": 1000,
"name": "Service Agreement",
"updated_at": "2026-02-20T09:00:00Z",
"documents": [{
"id": 1,
"filename": "agreement_v2.pdf"
}]
}| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The template ID (in URL path) |
Archives the template. Archived templates can be restored from the dashboard. Returns the archived template object.
{
"id": 1000,
"name": "Service Agreement",
"archived_at": "2026-02-20T09:00:00Z"
}
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.
| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The template ID (in URL path) |
| expires_in | Integer | Session TTL in seconds (default: 3600, max: 86400) |
| allowed_fields | Array<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] | String | Hex color for the Done button and accents (default: #4f46e5) |
| theme[logo_url] | String | URL to your logo shown in the editor topbar |
| theme[button_label] | String | Label for the primary action button (default: Done) |
| webhook_url | String | URL to receive a POST when the template is saved. Payload includes template_id, field_count, and your metadata. |
| submitter_name | String | Scope 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. |
| metadata | Object | Arbitrary key/value pairs echoed back in every postMessage event and webhook payload. Useful for correlating sessions with your own records. |
{
"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 type | When fired |
|---|---|
| editor.ready | Builder fully mounted and interactive |
| editor.saved | Auto-save completed successfully |
| editor.done | User clicked the Done button (final save triggered) |
| editor.field.added | A field was placed on the document |
| editor.field.removed | A field was deleted |
| editor.error | A save attempt failed |
| editor.fields | Response to editor.command.get_fields |
| editor.navigate | The 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 type | Effect |
|---|---|
| editor.command.save | Trigger an immediate save |
| editor.command.get_fields | Request current fields array (fires editor.fields back) |
| editor.command.get_template | Request 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(); } });
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.
| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The template ID (in URL path) |
{
"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
}]
}Append a new document to an existing template. To replace or remove existing documents use PUT /api/templates/{id}/documents instead.
| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The template ID (in URL path) |
| filerequired | String | Base64-encoded file content or a publicly accessible URL |
| name | String | Display name for the document |
| position | Integer | Zero-based insert position among existing documents |
Add a new fillable field to the template. Coordinates are expressed as fractions of the page dimensions (0.0–1.0).
| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The template ID (in URL path) |
| typerequired | String | Field type: text, signature, date, number, checkbox, radio, select, initials, image, stamp, phone, file, payment, cells |
| name | String | Display name (auto-generated if omitted) |
| page | Integer | Zero-based page index (default: 0) |
| x | Float | Horizontal position as a fraction of page width (default: 0.1) |
| y | Float | Vertical position as a fraction of page height (default: 0.1) |
| width | Float | Field width as a fraction of page width |
| height | Float | Field height as a fraction of page height |
| submitter_uuid | String | UUID of the template submitter (role) this field belongs to. Defaults to the first submitter. |
| required | Boolean | Whether the field must be filled before submission (default: true) |
{
"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"
}| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The template ID (in URL path) |
| field_uuidrequired | String | The field UUID to remove (in URL path) |
{"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.
| Parameter | Type | Description |
|---|---|---|
| submission_id | Integer | Filter by submission |
| q | String | Search by name, email, or phone |
| completed_after | String | Filter submitters completed after this date (ISO 8601) |
| completed_before | String | Filter submitters completed before this date (ISO 8601) |
| external_id | String | Filter by external ID |
| limit | Integer | Results per page (default: 10, max: 100) |
| after | Integer | Cursor ID — returns submitters with ID greater than this value |
| before | Integer | Cursor ID — returns submitters with ID less than this value |
{
"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
}
}| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The 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.
{
"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": {}
}| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The submitter ID (in URL path) |
| name | String | Submitter full name |
| String | Updated email address | |
| phone | String | Updated phone number (E.164 format) |
| external_id | String | Your application-specific unique key |
| values | Object | Pre-filled field values |
| metadata | Object | Custom key-value metadata |
| send_email | Boolean | Re-send invitation email after update |
| send_sms | Boolean | Re-send invitation via SMS after update |
| completed | Boolean | Mark submitter as completed (auto-sign) |
{
"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.
Merge multiple PDF files into a single PDF document. Accepts base64-encoded PDF files and returns a single merged PDF.
| Parameter | Type | Description |
|---|---|---|
| filesrequired | Array | Array of base64-encoded PDF files to merge (minimum 2) |
{
"data": "JVBERi0xLjQKMS..."
}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.
| Parameter | Type | Description |
|---|---|---|
| filerequired | String | Base64-encoded PDF file content |
{
"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."]
}]
}Convert a DOCX or HTML file to PDF. Returns a signed download URL valid for 1 hour.
| Parameter | Type | Description |
|---|---|---|
| filerequired | String or File | Base64-encoded DOCX/HTML file content, a publicly accessible URL, or a multipart upload. Supported extensions: .docx, .html |
| filename | String | Required when providing a raw base64 string so the converter knows the file type (e.g. document.docx) |
{
"url": "https://app.zignature.io/blobs/...",
"filename": "document.pdf"
}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.
| Parameter | Type | Description |
|---|---|---|
| template_idrequired | Integer | Template to send |
| recipientsrequired | Array | Array of recipient objects, max 100. Each requires email and optionally name, record_id (CRM record for merge fields) |
| provider | String | CRM provider for field value resolution: salesforce, hubspot, pipedrive, zoho_crm |
| object_type | String | CRM object type (default: Contact) |
{
"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"}
]
}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.
| Parameter | Type | Description |
|---|---|---|
| template_idrequired | Integer | Template to use for all submissions |
| submittersrequired | Array | Array of submitter objects (max 100). Each requires email and optionally name, values, metadata, external_id |
{
"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"
}
]
}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.
| Parameter | Type | Description |
|---|---|---|
| filerequired | File | The file to upload (multipart/form-data) |
| name | String | Optional display name for the file |
{
"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.
Retrieve form completion events. Returns submitter data with documents and attachments. Paginated by completion timestamp.
| Parameter | Type | Description |
|---|---|---|
| typepath | String | Event type filter: completed |
| after | Integer | Unix timestamp — return events after this time |
| before | Integer | Unix timestamp — return events before this time |
| limit | Integer | Number of events to return (default: 10) |
{
"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
}
}Retrieve submission completion events. Only returns submissions where all submitters have completed. Paginated by completion timestamp.
| Parameter | Type | Description |
|---|---|---|
| typepath | String | Event type filter: completed |
| after | Integer | Unix timestamp — return events after this time |
| before | Integer | Unix timestamp — return events before this time |
| limit | Integer | Number of events to return (default: 10) |
{
"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.
Fetches CRM record data including fields, values, and related objects. Supports Salesforce, HubSpot, Pipedrive, and Zoho CRM.
| Parameter | Type | Description |
|---|---|---|
| providerrequired | String | CRM provider: salesforce, hubspot, pipedrive, zoho_crm |
| record_idrequired | String | The CRM record ID |
| object_type | String | CRM object type (default: Contact) |
Uses AI heuristics to map CRM record fields to template fields with confidence scores. Supports line items and related records.
| Parameter | Type | Description |
|---|---|---|
| template_idrequired | Integer | Template ID to map fields for |
| crm_fieldsrequired | Object | CRM field key-value pairs |
| line_items | Array | Product/line item data |
| related_records | Object | Related record data (Account, Contact) |
Creates a submission from a template and sends to recipients. Supports CRM field values, line items, and writeback for edited values.
| Parameter | Type | Description |
|---|---|---|
| template_idrequired | Integer | Template to send |
| recipientsrequired | Array | List of signers (email, name) |
| field_values | Object | Pre-filled field values |
| crm_context | Object | CRM context (provider, record_id, object_type) |
Returns all documents associated with a CRM record including signer status, progress, and CRM context.
Returns the complete audit trail for a document including sent, viewed, signed, declined, and reassigned events.
Reassigns a pending signer to a different person. Marks original as declined/reassigned, sends invitation to new signer.
| Parameter | Type | Description |
|---|---|---|
| submitter_idrequired | Integer | Submitter ID to reassign |
| emailrequired | String | New signer email |
| name | String | New signer name |
| reason | String | Reason for reassignment |
Returns field schema for a CRM object type. Supports custom objects across all 4 CRM providers.
Returns a download URL for the signed document PDF.
Returns the profile of the authenticated user including account settings, CRM connections, and feature flags relevant to the extension.
{
"id": 6,
"email": "user@company.com",
"first_name": "Erik",
"last_name": "Hanson",
"account_id": 1,
"features": {
"deal_desk": true,
"bulk_send": true
}
}Returns the list of templates available to the authenticated user, optimized for the CRM extension context (includes role names and field summaries).
| Parameter | Type | Description |
|---|---|---|
| q | String | Search templates by name |
[{
"id": 1000,
"name": "Service Agreement",
"submitters": [{"name": "Customer"}],
"fields": [...]
}]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.
| Parameter | Type | Description |
|---|---|---|
| template_idrequired | Integer | Template ID to preview |
| field_values | Object | Key-value pairs of field names and values to pre-fill in the preview |
{
"url": "https://app.zignature.io/templates/1000/preview?token=..."
}Uses AI to analyze a template and suggest which CRM fields should be fetched to populate it. Returns field names ranked by relevance.
| Parameter | Type | Description |
|---|---|---|
| template_idrequired | Integer | Template ID to analyze |
| object_type | String | CRM object type to suggest fields from (e.g. Contact, Opportunity) |
| provider | String | CRM provider: salesforce, hubspot, pipedrive, zoho_crm |
{
"fields": ["FirstName", "LastName", "Email", "Company"]
}Re-sends the signature request email to a specific pending submitter.
| Parameter | Type | Description |
|---|---|---|
| submitter_idrequired | Integer | The submitter ID to resend the notification to |
{"sent": true}Updates the email, name, or phone of a pending submitter without reassigning them. The submitter retains their signing link and position.
| Parameter | Type | Description |
|---|---|---|
| submitter_idrequired | Integer | The submitter ID to update |
| String | New email address | |
| name | String | New full name |
| phone | String | New phone number |
Re-sends the signature request email to all pending (unsigned) submitters on a document.
| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The submission ID (in URL path) |
{"sent": true}Voids a pending submission, cancelling all remaining signing requests and notifying signers. Voided submissions cannot be reopened.
| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The submission ID (in URL path) |
| reason | String | Optional reason for voiding shown to signers |
Saves CRM writeback rules for a template — defining which signed field values should be written back to which CRM fields upon completion.
| Parameter | Type | Description |
|---|---|---|
| template_idrequired | Integer | Template to configure writeback for |
| rulesrequired | Array | Array of rule objects. Each has field_name (template field) and crm_field (CRM field key) |
| provider | String | CRM provider the rules apply to |
| object_type | String | CRM object type to write back to |
{
"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.
| Parameter | Type | Description |
|---|---|---|
| limit | Integer | Results per page (default: 10, max: 100) |
| after | Integer | Cursor — returns profiles with ID greater than this value |
| before | Integer | Cursor — returns profiles with ID less than this value |
{
"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
}
}| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The brand profile ID |
{
"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"
}| Parameter | Type | Description |
|---|---|---|
| namerequired | String | Internal label for this profile (e.g. River Realty) |
| sender_name | String | Name shown in the email "From" field. Defaults to name if omitted. |
| reply_to | String | Reply-to email address so signer replies go directly to the client |
| logo_url | String | Public URL to the client logo shown at the top of invitation emails. Recommended: 400×104px PNG, white or light-colored on a transparent background. |
{
"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"
}| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The brand profile ID |
| name | String | Internal label |
| sender_name | String | Email "From" display name |
| reply_to | String | Reply-to email address |
| logo_url | String | Public logo URL |
{
"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"
}| Parameter | Type | Description |
|---|---|---|
| idrequired | Integer | The brand profile ID |
Deletes the profile. Existing submissions that referenced this profile are unaffected — emails already sent retain their branding.
{
"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.
Retrieves the current deal desk review for a CRM record including status, risk score, drift analysis, approval chain, and activity timeline.
| Parameter | Type | Description |
|---|---|---|
| providerrequired | String | CRM provider |
| record_idrequired | String | CRM record ID |
| object_type | String | CRM object type |
{
"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"
}]
}Approves the current pending approval level. Advances to next level or completes the review if all levels approved.
| Parameter | Type | Description |
|---|---|---|
| comment | String | Optional approval comment |
Rejects the current pending approval level. Comment is required.
| Parameter | Type | Description |
|---|---|---|
| commentrequired | String | Rejection reason |
Sends a deal review back to the requester for changes. Comment is required.
| Parameter | Type | Description |
|---|---|---|
| commentrequired | String | Explanation of what needs revision |
Webhooks
Receive real-time HTTP POST notifications when events occur. Configure webhook URLs and secrets in Settings → Webhooks.
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.
| Detail | Value |
|---|---|
| Base URL | https://app.zignature.io/api/scim/v2 |
| Auth header | Authorization: Bearer YOUR_SCIM_TOKEN |
| Content-Type | application/scim+json |
Discovery Endpoints
| Endpoint | Description |
|---|---|
| GET /ServiceProviderConfig | Returns supported SCIM features (Patch, Bulk, Filter) |
| GET /ResourceTypes | Lists supported resource types: User and Group |
| GET /Schemas | Full JSON schemas for User and Group resources |
Users
Returns a paginated list of provisioned users. Supports SCIM filtering with filter parameter (e.g. userName eq "user@example.com").
| Parameter | Type | Description |
|---|---|---|
| filter | string | SCIM filter expression (e.g. userName eq "user@example.com") |
| startIndex | integer | 1-based pagination offset (default: 1) |
| count | integer | Number of results per page (default: 100) |
{
"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
}]
}Retrieve a single user by their UUID.
{
"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"
}
}Provision a new user in the account. If a previously archived user matches the email, they will be reactivated.
| Parameter | Type | Description |
|---|---|---|
| userName required | string | User’s email address |
| name.givenName | string | First name |
| name.familyName | string | Last name |
| emails | array | Array of email objects with value and primary fields |
{
"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
}Full replacement of a user resource. Setting active: false archives the user.
| Parameter | Type | Description |
|---|---|---|
| userName required | string | User’s email address |
| name.givenName | string | First name |
| name.familyName | string | Last name |
| active | boolean | Set to false to deactivate/archive |
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"userName": "jane@example.com",
"active": true
}Partial update using SCIM Patch operations. Supported ops: add, replace.
| Parameter | Type | Description |
|---|---|---|
| Operations required | array | Array of patch operations with op, path, and value |
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"userName": "jane@example.com",
"active": false
}Archive (soft-delete) a user. The user can be reactivated by creating a new user with the same email.
Groups
Returns a paginated list of groups (teams). Supports SCIM filtering with filter parameter.
| Parameter | Type | Description |
|---|---|---|
| filter | string | SCIM filter expression (e.g. displayName eq "Engineering") |
| startIndex | integer | 1-based pagination offset (default: 1) |
| count | integer | Number of results per page (default: 100) |
{
"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" }
]
}]
}Retrieve a single group (team) by UUID, including its member list.
{
"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"
}
}Create a new group (team) and optionally assign members by their user UUIDs.
| Parameter | Type | Description |
|---|---|---|
| displayName required | string | Name of the group/team |
| members | array | Array of objects with value (user UUID) |
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"id": "d4e5f6a7-b8c9-0123-defa-234567890123",
"displayName": "Sales",
"members": []
}Full replacement of a group resource. Replaces the group name and entire member list.
| Parameter | Type | Description |
|---|---|---|
| displayName required | string | Group name |
| members | array | Complete member list (replaces existing) |
{
"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" }
]
}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"]).
| Parameter | Type | Description |
|---|---|---|
| Operations required | array | Array of patch operations with op, path, and value |
{
"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" }
]
}Archive (soft-delete) a group and remove all member associations.
SDKs & Libraries
Use the Zignature API with your preferred language. All code examples use standard HTTP libraries — no SDK installation required.
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.
POST https://app.zignature.io/mcp
JSON-RPC 2.0 · MCP version 2025-03-26
Streamable HTTP (single endpoint)
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.
| Header | Value | Description |
|---|---|---|
| X-Auth-Token required | string | Your Zignature API token. Found in Developer Portal → API Keys. |
| Content-Type required | string | Must 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.
| Header | Value | Description |
|---|---|---|
| Authorization required | string | Bearer <access_token> — obtained via the OAuth 2.0 PKCE flow described in the OAuth section. |
| Content-Type required | string | Must 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)
| Tool | Description | Key Parameters |
|---|---|---|
| list_templates | List templates with search and folder filtering | query, folder |
| get_template | Get template details, fields, and roles | template_id |
| create_template | Create a new template with roles | name |
| update_template | Update name or move to folder | template_id |
| archive_template | Archive a template | template_id |
| restore_template | Restore an archived template | template_id |
| clone_template | Clone a template with all fields | template_id |
| suggest_template | Find templates by description | description |
Folders (3 tools)
| Tool | Description | Key Parameters |
|---|---|---|
| list_folders | List all template folders | — |
| create_folder | Create a new folder | name |
| rename_folder | Rename an existing folder | folder_id, name |
Documents & Signing (9 tools)
| Tool | Description | Key Parameters |
|---|---|---|
| send_document | Send document for signature | template_id, submitters |
| bulk_send_document | Send to up to 100 recipients | template_id, recipients |
| list_documents | List submissions with status filters | status, query |
| get_document_status | Detailed signer progress | submission_id |
| void_document | Cancel a pending document | submission_id |
| download_document | Get signed PDF download URLs | submission_id |
| get_audit_trail | Full event timeline with IPs | submission_id |
| send_reminder | Remind pending signers | submission_id |
| archive_document | Archive a submission | submission_id |
Users & Teams (7 tools)
| Tool | Description | Key Parameters |
|---|---|---|
| list_users | List account users | status, role |
| invite_user | Invite a new user | email |
| update_user | Update user name or role | user_id |
| deactivate_user | Deactivate a user | user_id |
| list_teams | List all teams | — |
| create_team | Create a new team | name |
| manage_team_members | Add or remove team members | team_id, action, user_id |
Webhooks (5 tools)
| Tool | Description | Key Parameters |
|---|---|---|
| list_webhooks | List webhook endpoints | — |
| create_webhook | Create a webhook | url |
| update_webhook | Update webhook URL | webhook_id, url |
| delete_webhook | Delete a webhook | webhook_id |
| test_webhook | Send test event | webhook_id |
Account, Branding & Billing (4 tools)
| Tool | Description | Key Parameters |
|---|---|---|
| get_account | Account details, branding, subscription | — |
| update_account | Update name, timezone, locale | name, timezone |
| update_branding | Change brand color | primary_color |
| get_billing | Plan, usage, subscription status | — |
Contracts / CLM (8 tools)
| Tool | Description | Key Parameters |
|---|---|---|
| list_contracts | List contracts with filters | status, counterparty |
| get_contract | Full contract details with parties and versions | contract_id |
| create_contract | Create a draft contract | title |
| update_contract | Update contract details | contract_id |
| transition_contract | Change contract status | contract_id, new_status |
| delete_contract | Delete a contract | contract_id |
| get_contract_dashboard | Pipeline stats and trends | — |
| promote_submission_to_contract | Create contract from signed doc | submission_id |
Deal Desk (6 tools)
| Tool | Description | Key Parameters |
|---|---|---|
| get_deal_desk_dashboard | Pending reviews, approval rates, pipeline | — |
| list_deal_desk_reviews | List reviews with filters | status, risk_level |
| get_deal_desk_review | Full review with approvals | review_id |
| action_deal_desk_review | Approve, reject, or send back | review_id, action |
| list_deal_desk_policies | List approval policies | — |
| get_deal_desk_analytics | Approval rates and trends | period |
Clause Library (4 tools)
| Tool | Description | Key Parameters |
|---|---|---|
| list_clauses | List clauses with category/search | category, query |
| create_clause | Add a clause to the library | title, content |
| update_clause | Update an existing clause | clause_id |
| delete_clause | Remove a clause | clause_id |
Other (3 tools)
| Tool | Description | Key Parameters |
|---|---|---|
| list_notifications | Recent user notifications | unread_only |
| get_submission_events | Detailed event log | submission_id |
| search_contacts | Search past recipients | query |
Notarization (7 tools)
| Tool | Description | Key Parameters |
|---|---|---|
| request_notarization | Request a RON session — invites a notary and sends the signer join link | submission_id, notary_email |
| get_notarization_status | Get full session status, URLs, and bundle details | submission_id |
| cancel_notarization | Cancel a pending or active notarization session | submission_id |
| resend_notary_invitation | Resend the notary invitation email | submission_id |
| list_notarization_sessions | List sessions for the account, filterable by status | status, limit |
| add_to_notarization_bundle | Add a document to a pending notarization bundle | submission_id, bundle_submission_id |
| remove_from_notarization_bundle | Remove a document from a pending notarization bundle | submission_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.
- Go to claude.ai → Settings → Integrations.
- Click Add custom integration and paste:
https://app.zignature.io/mcp - claude.ai will redirect you to Zignature to log in and approve access.
- 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
- Go to chatgpt.com/gpts/editor and create a new GPT.
- Click Configure → Create new action.
- Click Import from URL and paste:
https://app.zignature.io/openapi/chatgpt - Under Authentication, select API Key, set Header to
X-Auth-Token, and paste your API token. - 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