Start here
The API lives at https://api.bsign.ca/v1. Everything you send and get back is JSON, times are ISO 8601 in UTC.
- In bSign, open Settings > API & webhooks and create a token. It's shown once: keep it somewhere safe, like a password.
- Send it with every request as
Authorization: Bearer <token>. - Check it works:
curl https://api.bsign.ca/v1/me \
-H "Authorization: Bearer bsign_..."
{ "id": "fL3S02MVAQ", "name": "Jordan Office", "email": "jordan@example.com",
"site": { "id": "ATCuMMWmob", "name": "Example Dental" } }
A token acts as the person who created it: their templates (and those shared with them) and the documents they send. Make one per integration so each can be revoked on its own. Tokens last a year at most, and stop working if the account is disabled.
Send from a template
Set the document up once in bSign as a template, with a role for each recipient (Client, Manager…) and its fields. Then:
GET /templateslists your templates.GET /templates/{id}shows one's roles, and its fields with their types and choices.POST /templates/{id}/sendmakes the document and sends it. Give someone for every role the template leaves open, and values for its fields by name.
curl -X POST https://api.bsign.ca/v1/templates/T9x8Y7w6V5/send \
-H "Authorization: Bearer bsign_..." \
-H "Content-Type: application/json" \
-d '{
"reference": "Q-11520",
"recipients": [
{ "role": "Client", "name": "Jane Client", "email": "jane@acmedental.example" }
],
"fields": {
"Company name": "Acme Dental",
"Start date": "2026-10-01",
"Plan": "Business"
}
}'
The answer is the new document (201 Created), out for signature. What goes in fields:
- Fields the template fills in before sending are drawn into the document. Required ones must be given.
- A recipient's own fields start with the value, and they can change it while signing.
"Client::Job title"picks one role's field when two share a name. - Dates as
2026-10-01(or in the field's own format), checkboxes as a list of choices, dropdowns and radio buttons as one of the choices. Empty values are left out.
Other options: name, note, expiresInDays (1 to 365), sendInOrder, and sendEmails: false to send no emails and get each recipient's signing link back instead (to send by text message, for example). If anything is missing or wrong, the answer is 422 with every problem listed.
Follow documents
GET /documentslists the documents you sent, most recently changed first. Filter bystatus(in_progress,completed,declined,voided,expired,draft),reference,templateId,searchorupdatedSince.GET /documents/{id}has each recipient's status (sent,viewed,signed,waitingfor their turn…) and when they signed.GET /documents/{id}/filedownloads the PDF: signed and sealed once completed.GET /documents/{id}/certificatedownloads the completion certificate.POST /documents/{id}/remindemails whoever still has to sign.POST /documents/{id}/voidstops it, with areasonthe recipients are told.GET /documents/{id}/historyis everything that happened to it.
Webhooks
Rather than asking every few minutes, let bSign tell you. Add a webhook in Settings > API & webhooks, or with POST /webhooks, and bSign POSTs each event to your address as it happens:
{
"id": "Xb3kQ9pLmN",
"event": "document.completed",
"createdAt": "2026-09-29T16:20:00.000Z",
"document": { "id": "a1B2c3D4e5", "name": "Managed Services Agreement",
"reference": "Q-11520", "status": "completed" },
"actor": { "name": "Jane Client", "email": "jane@acmedental.example", "role": "recipient" }
}
The events: document.sent, viewed, signed, approved, declined, voided, completed, recipient_changed, reminder_sent, expiry_notice, expiry_extended, corrected, skipped and paper_copy. A delivery that fails is tried again after 30 seconds and 2 minutes; id stays the same, so you can ignore repeats.
Each delivery is signed with the webhook's secret, in the X-bSign-Signature header: t=<unix time>,v1=<HMAC-SHA256 of "t.body">. Check it before trusting the event:
// Node.js, with the raw request body
const crypto = require("crypto");
const [t, v1] = req.get("X-bSign-Signature").split(",").map((p) => p.split("=")[1]);
const expected = crypto.createHmac("sha256", process.env.BSIGN_WEBHOOK_SECRET)
.update(`${t}.${rawBody}`).digest("hex");
const valid = v1.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected))
&& Math.abs(Date.now() / 1000 - Number(t)) < 300; // not an old replay
GET /events?type=document.completed lists the latest events in the same shape, for tools that would rather ask.
All endpoints
| Request | What it does |
|---|---|
GET/me | Who the token belongs to |
GET/templates | Your templates |
GET/templates/{id} | A template's roles and fields |
GET/templates/{id}/schema | Its send request as a JSON Schema |
POST/templates/{id}/send | Send a document from it |
GET/documents | Your documents, with filters |
GET/documents/{id} | A document and its recipients |
GET/documents/{id}/file | Its PDF |
GET/documents/{id}/certificate | Its completion certificate |
GET/documents/{id}/history | What happened to it |
POST/documents/{id}/remind | Remind whoever still has to sign |
POST/documents/{id}/void | Void it, with a reason |
GET/events | The latest events |
GET/webhooks | Your webhooks |
POST/webhooks | Add one (url, events) |
DELETE/webhooks/{id} | Remove one |
Every field is described in the OpenAPI file, api.bsign.ca/v1/openapi.json: import it into Postman, Insomnia or your code generator.
Errors and limits
Anything other than a success comes back as { "error": { "code", "message" } }, with the problems listed in details.problems when there are several:
401no token, or it was revoked or has expired;404not found, or not yours;409not possible now (reminding a finished document, a certificate before completion);422something missing or wrong in what you sent;402the site's plan allowance is used up;429too many requests: 300 a minute per token, and 200 documents sent every 10 minutes.
Power Automate
bSign's connector for Microsoft Power Automate works today as a custom connector in your own Microsoft 365, no approval needed. Flows can send documents from your templates, start when a document is signed, completed or declined, and file the signed PDF wherever you like.
- In bSign, open Settings > API & webhooks and create a token named "Power Automate". Flows act as you: your templates and the documents you send.
- Download bSign's connector definition and its icon.
- In make.powerautomate.com, open Data > Custom connectors > New custom connector > Import an OpenAPI file, name it bSign and choose the definition. On General, upload the icon and set the background colour to
#1758c9, then Create connector. - On Test, add a connection and paste your token. The trigger When a document event happens and the actions (Send document from template, Get document, Download document PDF and more) are now in your flows.
Rather use the command line? The whole connector as a zip works with Microsoft's paconn tool (paconn create --settings settings.json). To let colleagues use it, share the connector from Power Automate or add it to a solution.
Zapier
bSign's Zapier app starts Zaps when documents are sent, viewed, signed, completed, declined or voided, and sends documents from your templates as a step in any Zap, with their fields filled from the apps before it.
- Open bSign's Zapier invitation and accept it with your Zapier account.
- In bSign, open Settings > API & webhooks and create a token named "Zapier". Zaps act as you: your templates and the documents you send.
- In a Zap, choose bSign as a trigger or an action and paste the token when Zapier asks to connect.
bSign is in Zapier as an invitation-only app while it goes through Zapier's review for their public directory; the invitation gives you the same app.
Questions, or an integration you'd like us to build? support@binarium.ca