API Reference

Signbee is a document signing API built for AI agents. One API call sends a document for two-party e-signing — both parties sign, both receive a SHA-256 certified PDF.

No SDK, no client library, no build step. Use the native HTTP client in any language — fetch in JavaScript, requests in Python, http.Client in Go. See 20+ framework examples.

Base URL

https://signb.ee

Format

JSON in, JSON out

OpenAPI Spec

/openapi.json

Endpoints

4 total

Authentication

Signbee supports two modes: with or without an API key. You can start testing immediately without signing up.

With API key Recommended

Sender is pre-verified. Recipient gets the signing email immediately. Best for automated agent workflows and production integrations.

Without API key Quick start

Sender verifies via email OTP first. Good for testing and one-off documents.

Header (when using API key)
Authorization: Bearer YOUR_API_KEY

Ready for production?

Create a free account to get your API key and access the dashboard. 5 documents/month included.

Create free account

Endpoints

POST/api/v1/send

Send a document for two-party e-signing. Provide either markdown or a PDF URL.

Auth: Optional — Bearer token or email OTP

Required fields

recipient_name— Full name of the recipient
recipient_email— Email address of the recipient
markdown— Document content (min 10 chars, max 50KB)

Or use pdf_url instead of markdown to send an existing PDF

Required without API key

sender_name— Full name of the sender
sender_email— Email address of the sender

Optional fields

title— Document title (auto-extracted from first heading if omitted)
expires_in_days— Days until signing link expires (default: 7, max: 30)
pdf_url— URL to an existing PDF (alternative to markdown)
webhook_url— Webhook URL for document.signed events (Pro/Business only, Free returns 403)
curl
curl -X POST https://signb.ee/api/v1/send \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "markdown": "# Mutual NDA\n\nThis agreement...",
    "recipient_name": "Bob Smith",
    "recipient_email": "bob@acme.com"
  }'
JavaScript (fetch)
const res = await fetch("https://signb.ee/api/v1/send", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer YOUR_API_KEY",
  },
  body: JSON.stringify({
    markdown: "# Mutual NDA\n\nThis agreement...",
    recipient_name: "Bob Smith",
    recipient_email: "bob@acme.com",
  }),
});
const data = await res.json();
console.log(data.document_id);
Python (requests)
import requests

res = requests.post(
    "https://signb.ee/api/v1/send",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={
        "markdown": "# Mutual NDA\n\nThis agreement...",
        "recipient_name": "Bob Smith",
        "recipient_email": "bob@acme.com",
    },
)
print(res.json()["document_id"])
Response (with API key)
{
  "document_id": "cmm...",
  "status": "pending_recipient",
  "sender": "Alice Chen",
  "recipient": "Bob Smith",
  "expires_at": "2026-04-19T12:00:00.000Z"
}
POST/api/v1/generate

Generate a PDF from markdown without initiating a signing flow. Useful for previewing documents before sending.

Auth: Not required

Required fields

markdown— Document content (min 10 chars, max 50KB)
curl
curl -X POST https://signb.ee/api/v1/generate \
  -H "Content-Type: application/json" \
  -d '{"markdown": "# Invoice\n\nAmount: $500"}'
Response
{
  "document_id": "cmm...",
  "url": "https://signb.ee/view/cmm...",
  "expires_at": "2026-04-16T12:00:00.000Z"
}
GET/api/v1/documents/{id}

Get the current status, signing URLs, and PDF links for a document. Use this to poll for completion.

Auth: Required — Bearer token

curl
curl https://signb.ee/api/v1/documents/cmm... \
  -H "Authorization: Bearer YOUR_API_KEY"
Response
{
  "document_id": "cmm...",
  "status": "pending_recipient",
  "title": "Mutual NDA",
  "sender": { "name": "Alice Chen", "signed_at": "..." },
  "recipient": { "name": "Bob Smith", "signed_at": null },
  "original_pdf_url": "...",
  "signed_pdf_url": null,
  "signing_url": "https://signb.ee/sign/...",
  "expires_at": "...",
  "created_at": "..."
}
DELETE/api/v1/documents/{id}

Revoke a pending document. The signing link becomes invalid immediately.

Auth: Required — Bearer token

Response
{
  "success": true,
  "message": "Document revoked. The signing link is no longer valid."
}

Webhooks (Pro & Business)

Pro and Business plans can receive real-time notifications when documents are signed. Include webhook_url in your POST /api/v1/send request.

Free plan limitation

Free accounts receive HTTP 403 with {"error":"Webhooks require Pro or Business plan. Upgrade at https://signb.ee/dashboard","plan":"FREE"}

Setup

  1. Include webhook_url in your send request
  2. Save the webhook_secret from the response (format: whsec_<uuid>)
  3. When the recipient signs, Signbee POSTs to your webhook_url
Request with webhook_url
curl -X POST https://signb.ee/api/v1/send \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "# Agreement\n\nTerms...",
    "recipient_name": "Bob Smith",
    "recipient_email": "bob@acme.com",
    "webhook_url": "https://your-server.com/webhooks/signbee"
  }'
Response includes webhook_secret
{
  "document_id": "cmm...",
  "status": "pending_recipient",
  "sender": "Alice Chen",
  "recipient": "Bob Smith",
  "expires_at": "2026-09-05T12:00:00.000Z",
  "webhook_secret": "whsec_a1b2c3d4e5f6..."
}

Webhook Payload

Event: document.signed (only event currently supported)

{
  "event": "document.signed",
  "document_id": "cmm_...",
  "title": "Mutual NDA",
  "status": "signed",
  "sender_email": "alice@startup.com",
  "recipient_name": "Bob Smith",
  "recipient_email": "bob@acme.com",
  "recipient_signed_at": "2026-08-31T12:00:00.000Z",
  "signed_pdf_url": "https://signb.ee/uploads/signed_abc.pdf",
  "signature_hash": "e3b0c44298fc1c149afbf4c...",
  "verify_url": "https://signb.ee/verify/cmm_...",
  "timestamp": "2026-08-31T12:00:00.000Z"
}

Headers

Content-Type— application/json
X-Signbee-Signature— HMAC-SHA256 hex digest of raw POST body
X-Signbee-Event— document.signed
User-Agent— Signbee-Webhook/1.0

Signature Verification

Verify the X-Signbee-Signature header to confirm the webhook came from Signbee. Use timingSafeEqual to prevent timing attacks.

Node.js verification
const crypto = require("crypto");

function verifyWebhook(rawBody, signatureHeader, webhookSecret) {
  const expected = crypto
    .createHmac("sha256", webhookSecret)
    .update(rawBody)
    .digest("hex");
  
  return crypto.timingSafeEqual(
    Buffer.from(expected, "utf8"),
    Buffer.from(signatureHeader, "utf8")
  );
}

// In your Express handler:
app.post("/webhooks/signbee", express.raw({type: "application/json"}), (req, res) => {
  const signature = req.headers["x-signbee-signature"];
  const webhookSecret = process.env.SIGNBEE_WEBHOOK_SECRET;
  
  if (!verifyWebhook(req.body, signature, webhookSecret)) {
    return res.status(401).send("Invalid signature");
  }
  
  const payload = JSON.parse(req.body);
  console.log(`Document ${payload.document_id} signed!`);
  res.json({ received: true });
});

Delivery behavior:

  • 10-second timeout
  • Fire-and-forget (no automatic retries)
  • Polling via GET /api/v1/documents/{id} works as a fallback on all plans

Markdown Tables

GFM (GitHub Flavored Markdown) pipe tables are supported in markdown on all plans.

Markdown table example
| Item | Quantity | Price | Total |
|------|----------|-------|-------|
| Widget A | 5 | $10.00 | $50.00 |
| Widget B | 3 | $15.00 | $45.00 |
| Widget C | 2 | $25.00 | $50.00 |

Document Lifecycle

Every document moves through a predictable state machine. Poll GET /api/v1/documents/{id} to track progress. On Pro and Business plans, if you set webhook_url, Signbee also POSTs a document.signed event when the recipient signs.

StatusMeaning
draftPDF generated, no signing flow started
pending_senderAwaiting sender OTP verification
pending_recipientSender signed, awaiting recipient
signedBoth parties signed — signed_pdf_url available
expiredSigning link expired before completion
revokedCancelled via DELETE — signing link invalidated

The SHA-256 signing certificate is generated when status moves to signed. Both parties receive the certified PDF by email automatically.

How the Signing Flow Works

  1. 01Agent calls POST /api/v1/send with document content and party details
  2. 02With API key: sender is pre-verified, recipient gets signing email immediately
  3. 03Without API key: sender verifies via OTP, then recipient gets signing email
  4. 04Recipient clicks link, reviews the document, and signs
  5. 05Both parties receive the signed PDF with SHA-256 certificate via email

Agent Integrations

Beyond the REST API, Signbee exposes e-signing to AI agents through two additional protocols. For the full context on agent discoverability, see The Multi-Protocol Future.

MCP Server

Works with Claude Desktop, Cursor, Windsurf, and any MCP-compatible client. Exposes a send_document tool that AI agents can call without writing API code.

{
  "mcpServers": {
    "signbee": {
      "command": "npx",
      "args": ["-y", "signbee-mcp"],
      "env": { "SIGNBEE_API_KEY": "YOUR_API_KEY" }
    }
  }
}

npm: signbee-mcp · Guide: 2-minute setup

llms.txt

Machine-readable product description for AI agents. Tells LLMs what Signbee can do, how to call the API, and where to find docs — without scraping.

signb.ee/llms.txt · What is llms.txt?

Direct API

Call the REST API from any language. No SDK needed — just HTTP + JSON. See 20+ framework guides with copy-paste examples.

OpenAPI spec: signb.ee/openapi.json

Rate Limits

PlanDocuments / monthEmail rate
Free51 per minute
Pro ($9/mo)10010 per minute
Business ($19/mo)Unlimited30 per minute

When you hit a rate limit, the API returns 429 with a Retry-After header. Document limits reset on the 1st of each month.

Error Codes

CodeMeaning
400Missing or invalid fields
401Invalid API key
403Plan limit reached, webhook_url on Free plan, or unauthorized
429Email rate limit exceeded
503Email service temporarily unavailable

All error responses return JSON with an error field:{"error": "description"}

Questions?

hello@signb.ee

Last updated: 31 August 2026