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. Included in the $29/mo Business plan, not a separate metered developer product like most e-signature APIs.
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"
}
Already works with 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 Make's own connectors to each, not a native SignedBy integration.
Included in Business ($29/mo)
No separate developer plan or per-seat API tier — 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 (requires the Business plan). Send it as a bearer token on every request:
Authorization: Bearer sb_live_...
Missing or invalid keys get a 401. A key on a plan below Business gets a 402:
401 { "error": "Missing API key. Pass it as 'Authorization: Bearer <key>'." }
401 { "error": "Invalid API key." }
402 { "error": "API access requires the Business plan." }Endpoints
/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
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.
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.
Ready to build?
Sign up free, then upgrade to Business ($29/mo) whenever you're ready for your API key.
Start for free →