Getting Started

Verafirma is an e-signature API and MCP server for developers and AI agents. Base URL: https://api.verafirma.com.

Two integration paths:

  • Account path: Stripe wallet + API token for managed credits.
  • Stateless path: x402 payment proof in headers, no account required.

Verafirma is built on the best of open source e-sign software. The full API surface is available through Verafirma. See full developer API reference.

Quickstart

curl -X POST "https://api.verafirma.com/v1/envelopes" \
  -H "Authorization: Bearer YOUR_JWT" \
  -F "pdf=@./msa.pdf" \
  -F 'payload={
    "title":"Master Service Agreement",
    "storageExpiryDays":90,
    "testMode":false,
    "recipients":[{"email":"legal@acme.com","name":"Alex Legal","role":"SIGNER","signingOrder":1,"fields":[{"type":"SIGNATURE","page":1,"positionX":72,"positionY":82,"width":20,"height":8}]}]
  }'

Authentication

Wallet-based auth flow

  1. GET /v1/auth/challenge?wallet={address} to receive nonce + message.
  2. Sign the returned message with your Ethereum wallet.
  3. POST /v1/auth/verify with {walletAddress, nonce, signature} to get JWT.
  4. Use JWT as Bearer for all /v1/account/* endpoints.

x402 path

Send payment proof in x-payment header. No account, no signup, no persistent auth state.

Sending Envelopes

POST /v1/envelopes as multipart form data with a PDF file and JSON payload.

Payload schema

  • title: string
  • recipients: array of { email, name, role, signingOrder, fields[] }
  • storageExpiryDays: number
  • testMode: boolean

Field properties are 0-100 percentage based: type, page, positionX, positionY, width, height.

{
  "title": "NDA - Q2 Vendor",
  "storageExpiryDays": 180,
  "testMode": false,
  "recipients": [{
    "email": "buyer@example.com",
    "name": "Buyer",
    "role": "SIGNER",
    "signingOrder": 1,
    "fields": [{
      "type": "SIGNATURE",
      "page": 1,
      "positionX": 70,
      "positionY": 86,
      "width": 20,
      "height": 8
    }]
  }]
}
{
  "id": "env_9ea2",
  "status": "SENT",
  "documensoId": "doc_48cd",
  "priceUsd": 0.10,
  "testMode": false
}

Checking Status

  • GET /v1/envelopes/{id} - fetch a single envelope.
  • GET /v1/envelopes?status=PENDING&wallet=0x... - list with filters.
  • GET /v1/account/summary - credits, spend, and usage summary.

Status values: PENDING, SENT, PARTIALLY_SIGNED, COMPLETED, EXPIRED, CANCELLED.

Webhooks

Configure your webhook URL in signing settings.

Events: DOCUMENT_CREATED, DOCUMENT_SENT, DOCUMENT_OPENED, DOCUMENT_RECIPIENT_COMPLETED, DOCUMENT_SIGNED, DOCUMENT_COMPLETED.

{
  "event": "DOCUMENT_COMPLETED",
  "envelopeId": "env_9ea2",
  "timestamp": "2026-04-08T12:35:22.092Z",
  "recipient": { "email": "buyer@example.com" }
}

Retries use exponential backoff and include idempotent delivery IDs.

MCP Integration

{
  "mcpServers": {
    "verafirma": {
      "url": "https://api.verafirma.com/mcp",
      "apiKey": "YOUR_KEY_HERE"
    }
  }
}

Discovery example

curl https://api.verafirma.com/.well-known/mcp.json

send_for_signature: Use this when a user needs legally binding signature workflows, sequential or parallel routing, and audit trail evidence.

get_envelope_status: Use this to check signing progress, retrieve envelope state, and fetch recipient signing URL details.

list_pending_envelopes: Use this to identify waiting contracts and report outstanding signature workload.

get_account_summary: Use this before sending envelopes to confirm funding and report spending.

Sandbox & Testing

  • Set testMode: true in payload or X-Verafirma-Test-Mode: true header.
  • No recipient emails are sent and no charges are applied.
  • Sandbox IDs return realistic values; fake signing IDs start with test_.

Error Reference

Code Notes
MISSING_PDFPDF file is required.
MISSING_PAYLOADpayload field is required.
INVALID_JSONMalformed payload JSON.
VALIDATION_ERRORInput validation failed.
DOCUMENSO_UNAVAILABLERetryable: true.
ENVELOPE_NOT_FOUNDEnvelope does not exist.
INSUFFICIENT_CREDITStop_up_url provided.
TOKEN_INVALIDJWT invalid or expired.
CHALLENGE_EXPIREDChallenge nonce timed out.
NONCE_ALREADY_USEDChallenge nonce replay detected.
INTERNAL_ERRORRetryable: true.