Sign inBuild on SignedBy. Fast.
A REST API and outbound webhooks for wiring SignedBy into your CRM, app, or onboarding flow — create and send documents, get notified the moment one's signed, and sync it all back automatically. Starts on the $7/mo Pro plan (100 free document-sends a month, then billed per document) and becomes fully unlimited on Business ($29/mo) — no separate developer plan to buy first.
Start for free →No credit card required — 3 free documents every month to try it.
$ curl -X POST https://signedby.ai/api/v1/documents \
-H "Authorization: Bearer sb_live_..." \
-d '{"template_id":"3c78a1e4-...","signer":{"email":"jane@acme.com"}}'
{
"id": "7fdd90eb-9152-4031-a767-c0632126dc53",
"status": "sent"
}
A native app on Zapier, plus Pipedrive, HubSpot, Airtable, Notion, Attio, Brevo, and 1,500+ other apps via Make — see the Pipedrive walkthrough below.
Each is a trademark of its respective owner; SignedBy is not affiliated with or endorsed by any of them — they're reachable via Zapier's or Make's own connectors to each, not a native SignedBy integration (Zapier and Make themselves excepted).
Starts on Pro ($7/mo)
No separate developer plan or per-seat API tier — 100 free document-sends a month on Pro/Team, fully unlimited (plus webhooks) on Business ($29/mo). See how that compares to DocuSign, SignNow, and PandaDoc on our comparison pages.
REST + webhooks
Plain JSON over HTTPS, HMAC-signed outbound events. No SDK required.
No sandbox needed
The free tier's 3 documents/month is real enough to build and test against.
Rate limit
60 document creates per hour per org — plenty for real usage, generous for testing.
Authentication
Generate a key from Settings → Integration & API — every plan can generate one now, including Free. Send it as a bearer token on every request:
Authorization: Bearer sb_live_...
Missing or invalid keys get a 401. What happens after that depends on your plan: Business is unlimited, Pro and Team are metered (100 free document-sends/month, then billed per document — see /console for pricing), and Free is capped at the same 3 documents/month the dashboard gives you — extendable any time with a one-time $5 pack of 25 extra document credits (never expire, no subscription needed). A capped 402 carries a ready upgrade_urlStripe Checkout link right in the response, so paying doesn't mean leaving the API to go find billing in the dashboard:
401 { "error": "Missing API key. Pass it as 'Authorization: Bearer <key>'." }
401 { "error": "Invalid API key." }
402 { "error": "You've hit the Free plan's 3 documents/month limit. Upgrade to keep going.",
"upgrade_url": "https://checkout.stripe.com/..." }Endpoints
Prefer to import this into Postman, Insomnia, or a codegen tool? The full OpenAPI 3.0 specis generated straight from the same request-validation code this API runs — not hand-copied — so it can't drift from what's actually deployed. (First published 2026-09-12.)
/api/v1/documentsCreate a document from a template and send it to one signer.
Request
curl -X POST https://signedby.ai/api/v1/documents \
-H "Authorization: Bearer sb_live_..." \
-H "Content-Type: application/json" \
-d '{
"template_id": "3c78a1e4-dc56-4769-87f6-65e344dd6d8f",
"signer": { "email": "jane@acme.com", "name": "Jane", "auth_required": false },
"expires_at": "2026-08-15T00:00:00Z",
"invite_subject": "Please sign your Acme agreement",
"invite_message": "Thanks for your business — just one form to go."
}'Response
201
{
"id": "7fdd90eb-9152-4031-a767-c0632126dc53",
"status": "sent",
"expires_at": "2026-08-15T00:00:00Z",
"auth_required": false
}/api/v1/documentsMulti-party version — send the same template to 2+ role-tagged signers in one call. 'role' maps to the template's Party 1 / Party 2 / … field assignments.
Request
curl -X POST https://signedby.ai/api/v1/documents \
-H "Authorization: Bearer sb_live_..." \
-H "Content-Type: application/json" \
-d '{
"template_id": "3c78a1e4-dc56-4769-87f6-65e344dd6d8f",
"signers": [
{ "role": 0, "email": "buyer@acme.com", "name": "Buyer", "auth_required": true },
{ "role": 1, "email": "seller@acme.com", "name": "Seller", "auth_required": false }
]
}'Response
201
{
"id": "643d45b3-...",
"status": "sent",
"expires_at": null,
"signers": [
{ "id": "...", "role": 0, "email": "buyer@acme.com", "auth_required": true },
{ "id": "...", "role": 1, "email": "seller@acme.com", "auth_required": false }
]
}/api/v1/documents?status=completed&limit=20&offset=0List/search the org's documents. status is optional (draft, sent, completed, declined, voided); limit defaults to 20, max 100.
Request
curl "https://signedby.ai/api/v1/documents?status=completed&limit=20" \ -H "Authorization: Bearer sb_live_..."
Response
200
{
"documents": [
{ "id": "...", "title": "Freelance Agreement", "status": "completed",
"created_at": "2026-07-28T10:04:00Z", "updated_at": "2026-07-29T09:11:00Z",
"expires_at": null }
],
"total": 42,
"limit": 20,
"offset": 0,
"has_more": true
}/api/v1/documents/{id}Get a single document's status and its signers' progress.
Request
curl https://signedby.ai/api/v1/documents/<document-id> \ -H "Authorization: Bearer sb_live_..."
Response
200
{
"id": "...",
"title": "Freelance Agreement",
"status": "completed",
"created_at": "2026-07-28T10:04:00Z",
"updated_at": "2026-07-29T09:11:00Z",
"expires_at": null,
"signers": [
{ "email": "jane@acme.com", "name": "Jane", "status": "signed",
"signed_at": "2026-07-29T09:11:00Z", "auth_required": false, "auth_verified": false }
]
}/api/v1/templatesList the org's templates, for populating a dropdown in your own UI or a Make scenario.
Request
curl https://signedby.ai/api/v1/templates \ -H "Authorization: Bearer sb_live_..."
Response
200
{
"templates": [
{ "id": "3c78a1e4-...", "name": "Freelance Agreement", "page_count": 3,
"created_at": "2026-07-01T12:00:00Z" }
]
}/api/v1/documents/{id}/signed-fileDownload the completed, flattened PDF once every signer has signed. 404 until it's ready.
Request
curl https://signedby.ai/api/v1/documents/<document-id>/signed-file \ -H "Authorization: Bearer sb_live_..." -o signed.pdf
Response
200 <binary PDF>
404 { "error": "Signed PDF isn't ready yet." }/api/v1/documents/{id}/voidCancel a document that's out for signature — e.g. 'deal fell through, kill the pending contract.' Only works while status is 'sent'.
Request
curl -X POST https://signedby.ai/api/v1/documents/<document-id>/void \ -H "Authorization: Bearer sb_live_..."
Response
200 { "success": true }
400 { "error": "Only documents that are out for signature can be voided." }Webhooks
Available on Pro and higher (previously Business-only). Register one or more endpoint URLs in Settings → Webhooks (each gets its own signing secret). Every enabled endpoint receives all four document lifecycle events:
document.viewed— the signer opened the link for the first timedocument.signed— one signer completed their part (fires per signer, not just once)document.completed— every signer has finisheddocument.declined— a signer declined to sign
Payload shape — signer is omitted on document.completed, since that event isn't about one recipient:
{
"event": "document.signed",
"occurred_at": "2026-07-30T09:02:11.000Z",
"document_id": "7fdd90eb-9152-4031-a767-c0632126dc53",
"title": "Freelance Agreement",
"status": "sent",
"signer": { "email": "jane@acme.com", "name": "Jane" }
}Each delivery is signed with your endpoint's own secret via an X-SignedBy-Signature header:
X-SignedBy-Signature: sha256=6f2c9e...
Verify it (Node.js) before trusting the payload:
const crypto = require("crypto");
function verify(rawBody, signatureHeader, secret) {
const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader));
}Delivery is fire-and-forget with one retry after a 1-second delay (5-second timeout per attempt) — there's no persistent delivery log or manual-redelivery UI yet, so make your endpoint idempotent and check the document's current status via GET /api/v1/documents/{id} if you need to reconcile a missed event.
MCP server (for AI agents)
SignedBy also runs a real Model Context Protocol (MCP) server — ten tools show up ready to call, wrapping the same endpoints above plus Verified Badge sealing and a usage check.
MCP server URL
https://signedby.ai/api/mcphttps://signedby.ai/api/mcpThis is the one thing every client below needs — paste it into a connector (OAuth) or your MCP config (API key).
Claude (claude.ai, Desktop, Cowork) — connect with OAuth, no API key
Add SignedBy as a custom connector with just the server URL below, and you'll be walked through logging into SignedBy and approving a consent screen — the same "this app wants access to your account" flow as connecting Slack or Google Drive. Nothing to copy-paste.
- Settings → Connectors → + → "Add custom connector" (or go straight to
claude.ai/settings/connectors) - Paste the server URL —
https://signedby.ai/api/mcp— and it detects OAuth automatically. The consent screen shows which SignedBy workspace you're connecting and exactly what's being granted: read-only access to documents and usage, the ability to send/seal/manage documents on your behalf, or both, depending on what the client asks for. Revoke it anytime from SignedBy's Settings → Connected apps.
Any other MCP client — connect with an API key
For Claude Code, or any MCP client that takes a plain URL and header rather than OAuth, add this to your MCP config:
{
"mcpServers": {
"signedby": {
"url": "https://signedby.ai/api/mcp",
"headers": { "Authorization": "Bearer sb_live_..." }
}
}
}The signer's side is completely unchanged — an AI agent can trigger a signing request through these tools, but the recipient still has to open the link and sign it themselves, through the same per-recipient verification as every other document. Every document an agent creates or voids through this server is tagged in the audit trail (an agent_triggeredflag alongside the usual event log), so it's always possible to tell an agent-initiated send apart from one a person sent directly.
list_templatesList the org's templates, to find a template_id for create_and_send_document.
create_and_send_documentCreate a document from a template and send it to one signer. Triggers the send only — the signer still opens the link and signs it themselves.
get_document_statusLook up a document's status and each signer's status by id.
list_documentsList the org's documents, optionally filtered by status.
void_documentCancel a document that's still out for signature (status must be 'sent').
get_signed_fileDownload the completed, signed PDF once every signer has finished.
seal_documentCertify a finished PDF as unaltered and identity-verified — hashes it, timestamps it, and returns a Verified Badge plus a public verification link. Not a signature request: it never asks anyone else to sign anything, it certifies a file the org already considers final. Requires a one-time Stripe Identity check on the org first. On Pro/Team it shares Console's metered allowance with create_and_send_document; on Business it's unlimited.
get_certificate_fileDownload the standalone certificate PDF from a seal — only exists when seal_document ran with certificate_mode 'separate' or 'both' (the default).
get_badge_imageDownload the Verified Badge PNG for a sealed document — the scannable proof badge, generated fresh from the audit trail.
get_usageCheck the org's plan and how much of its document allowance is left this period — read-only, no side effects.
Every tool here is available on every plan, including Free — MCP access itself isn't gated. What varies by plan is volume and templates. On Free: create_and_send_documentneeds an existing template, and Free orgs get exactly one self-saved template (there's no MCP tool to create one — save it once via the dashboard, then send with it here); usage of create_and_send_document and seal_document together is capped at 3 documents/month, extendable any time with a one-time $5 pack of 25 extra document credits (never expire, no subscription needed). Call get_usage any time to check the count without guessing, and if you do hit the cap, the error itself carries an upgrade_url— a ready Stripe Checkout link, so paying doesn't mean leaving the conversation to go find billing in the dashboard.
On Pro, Team, and Business: unlimited templates, and create_and_send_document usage rides on Console's metered access — 100 free document-sends/month, then billed per document, same metering on every plan including Business — not the plain REST API access described in Authentication above, which is metered on Pro/Team and unlimited on Business. See /console for the full pricing.
seal_document works differently by plan (updated 2026-08-28): on Free it shares the 3-document/ month allowance with sending, as above. On Pro and Team it now shares the same 100-free-then-billed Console allowance as create_and_send_document— sends and seals draw from one combined pool, and hitting your own spend cap returns a plain error asking you to raise or turn it off in the console (there's no credit pack to buy here — it's a self-set cap, not a plan limit). On Business, sealing stays fully unlimited and unmetered. It additionally needs a one-time Stripe Identity check on the org (from the dashboard's Settings page, not through this tool) before the first call succeeds, regardless of plan.
Connect via Zapier
A native SignedBy app on Zapier — no generic HTTP module or webhook copy-pasting needed. View SignedBy on Zapier → Three building blocks:
Trigger: New Document Completed
Fires when a document you sent finishes signing. Excludes documents you sealed yourself with a Verified Badge— those are certifications, not something a Zap should treat as "signed by everyone."
Action: Send Document
Pick a template, give it a recipient email, and it's out for signature — the same single-recipient path as POST /api/v1/documents. Multi-party sends aren't in this action yet; use the API directly for those.
Search: Find Document
Look up a document's status (and each recipient's) by ID mid-Zap — e.g. "before doing X, check whether this document has actually been signed yet."
Zapier is a trademark of Zapier Inc.; SignedBy is not affiliated with or endorsed by Zapier.
Connect via Make
There's no native SignedBy app in Make's marketplace yet — you don't need one for either direction:
SignedBy → Make
Add a Custom Webhook trigger module in Make, copy the URL it gives you, and paste it into Settings → Webhooks. Nothing to build on our side.
Make → SignedBy
Use Make's generic HTTP — Make a request module, with your API key as an Authorization: Bearer header, against any endpoint above.
How-to: Pipedrive, both directions
A worked example using Make to connect a Pipedrive deal to a SignedBy contract, start to finish — adapt the same shape for HubSpot, Airtable, or any other CRM.
1. Deal reaches "Contract sent" → send the contract
In Make: a Pipedrive trigger watching for deals entering your "Contract sent" stage, feeding into an HTTP — Make a request module that calls POST /api/v1/documents with the deal's contact as the signer. The contract is out for signature the moment the deal moves stage — no one has to remember to send it.
2. Contract signed → update the deal
A second Make scenario: a Custom Webhook trigger listening for document.completed, feeding into Pipedrive's Update a Deal (or Create a Note) module — logging that the contract came back signed, or moving the deal to its next stage automatically.
Pipedrive is a trademark of its respective owner; SignedBy is not affiliated with or endorsed by Pipedrive or Make.
FAQ & gotchas
What format does expires_at need?
A full UTC ISO-8601 datetime ending in Z — e.g. 2026-08-15T00:00:00Z. A timezone offset like +02:00 is rejected; convert to UTC first.
How does multi-party role numbering work?
role matches the Party 1 / Party 2 / … assignments already on the template — role 0 is Party 1, role 1 is Party 2, and so on. Every role actually used on the template needs a matching signer, or the request is rejected up front.
Is there a sandbox or test mode?
No — the free tier's 3 documents/month is real enough to build and test integrations against before upgrading.
What happens with auth_required signers?
That signer has to enter a one-time email code before the document opens at all — same per-recipient verification the dashboard offers, free on every plan.
Verify a sealed document independently
seal_documentabove and the dashboard's own Verified Badge both certify a finished PDF against a real, third-party Time Stamping Authority (RFC 3161) — not just a row in our own database. That means the result can be checked by anyone, without asking SignedBy or trusting our servers to tell the truth about our own documents.
The verification engine is open source and published as a zero-dependency npm package, verifiedby — run the exact same check inside your own app, or send a recipient to verifiedby.dev for the docs and API reference, or truedoc.eu to check a single file with nothing to install.
npm install verifiedby
import { verify } from "verifiedby";
const result = await verify(pdfBytes);
console.log(result.status);
// "verified" | "verified-untrusted-root" | "signed-untimed" |
// "unverified" | "mismatch" | "unsupported" | "no-signature"Full source, methodology, and the complete status-verdict rubric are on GitHub.
Ready to build?
Sign up free — you can generate a key today. Upgrade to Pro ($7/mo) for real usage, or Business ($29/mo) for unlimited access and webhooks.
Start for free →