SignMaster API
Signing, from your app.One key. Three calls.
Your server asks SignMaster for a one-time signing link, shows it in your page or sends the signer there, and reads the result when they're done.
On Crew and Company. New workspaces get 14 days of Crew free.
- POST/envelopes/ce53…/embedded-sessionsurl opens once, within 5 minutes201
- Signer signs inside your pagesigned
- Your page hears signmaster:completedmessage
- GET/envelopes/ce53…status: completed200
- Endpoints
- 3
- links, status and data
- Per key
- 60/min
- requests, every minute
- Signing links
- 5 min
- to open, and only once
- Plans
- Crew+
- Crew and Company
01
What you can do
You send envelopes from SignMaster on the web or in the app, the way you do today. The API picks it up from there.
Put signing in your app
Ask for a one-time signing link and show it in your page, or send the signer there and back.
POST /envelopes/{id}/embedded-sessions
Track every envelope
Who has signed, who hasn't, when it finished, and the fingerprint of the signed PDF.
GET /envelopes/{id}
Read what they entered
Every field signers filled in, by label and page, ready for your own records.
GET /envelopes/{id}/data
Every request goes to https://www.usesignmaster.app/api/v1 and answers in JSON.
02
Get a key
Keys live in Settings › Developers. You need the Connect apps permission; owners and admins always have it.
- 1
Create the key
Open Settings › Developers, choose Create key, name it after the app that will use it, and tick what it may do:
- embedded:create
- Start embedded signing. Create one-time signing links for a signer.
- envelopes:read
- Read envelopes. Status, signers and filled-in data for every envelope in the workspace.
- 2
Copy it once
The key starts with
sm_live_and is shown one time only; SignMaster keeps just a fingerprint of it. Store it on your server, in an environment variable such asSIGNMASTER_API_KEY. - 3
Allow your site
Under Allowed origins, add the site that shows signing or that signers come back to, like
https://app.example.com. Use https;http://localhostworks while you build.
Revoke a key in the same place. Anything using it stops working right away.
03
Authentication
Send the key as a Bearer token on every request. A key works only for its own workspace.
curl https://www.usesignmaster.app/api/v1/envelopes/ENVELOPE_ID \ -H "Authorization: Bearer $SIGNMASTER_API_KEY"Call the API from your server only. Browsers on other sites can't read its answers, and a key in a web page or an app can be copied by anyone.
04
Send a signing link
Right before a signer needs to sign, create a session for them and show it: inside your page, or by sending them there and back.
- 1
Find the envelope
Send the envelope from SignMaster as usual. Its ID is the last part of its address in SignMaster:
/envelopes/ce53b309-da39-4130-b663-ce9981cb7f4c. - 2
Create a session
Name the signer by
recipient_email(any capitalization) orrecipient_id, say where they land when they finish, and, to show it in your page, that page's origin. Needs theembedded:createpermission.curl -X POST https://www.usesignmaster.app/api/v1/envelopes/ENVELOPE_ID/embedded-sessions \ -H "Authorization: Bearer $SIGNMASTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "recipient_email": "dana@example.com", "return_url": "https://app.example.com/signed?order=1042", "frame_origin": "https://app.example.com" }'Response · 201 Created
{ "session_id": "5b51e98e-8189-4b71-b60a-1d45dc80e439", "url": "https://www.usesignmaster.app/embed/9Lr2…", "expires_at": "2026-10-11T16:13:18.186231+00:00", "expires_in_seconds": 300, "envelope_id": "ce53b309-da39-4130-b663-ce9981cb7f4c", "recipient": { "name": "Dana Lee", "email": "dana@example.com" }, "return_url": "https://app.example.com/signed?order=1042", "frame_origin": "https://app.example.com" }- recipient_email
- The signer's email. Or pass recipient_id instead.
- return_url
- Required. An absolute https URL on one of your allowed origins, where a signer who isn't in a frame lands. Your own query string is kept.
- frame_origin
- Optional. The origin of the page that will show signing in a frame, like https://app.example.com. Must be one of your allowed origins. Leave it out to redirect instead.
The link opens once, within 5 minutes, so create it when the signer chooses to sign. It must be their turn: with signers in order, asking for the second before the first has signed returns
not_their_turn. - 3
Show it in your page
Put
urlin a frame on the page you named asframe_origin. SignMaster tells that page what happened with a message.Your page<iframe src="SESSION_URL" title="Sign the document" style="width: 100%; height: 760px; border: 0"></iframe><script> window.addEventListener("message", (event) => { if (event.origin !== "https://www.usesignmaster.app") return; switch (event.data?.type) { case "signmaster:loaded": /* hide your spinner */ break; case "signmaster:completed": /* close the frame, then check status */ break; case "signmaster:declined": /* the signer said no */ break; case "signmaster:error": /* event.data.code: link_used or session_expired */ break; } });</script>- signmaster:loaded
- The signing page is ready. view is "signing", or "access_gate" when the signer must enter an access code first.
- signmaster:completed
- They signed. envelope_status is "completed", or "waiting_for_others" when others still have to.
- signmaster:declined
- They declined to sign.
- signmaster:error
- code is link_used or session_expired. Create a new session.
The framing rules
- 1.Only the origin in
frame_origincan show the session. The browser refuses every other site, and a session made withoutframe_origincan't be framed anywhere. - 2.
frame_originmust be one of your allowed origins. Remove an origin and the links already made for it stop working there at once. - 3.Messages go to that origin only. Check that
event.originishttps://www.usesignmaster.appbefore you trust one. - 4.A message is a hint for your interface. Check the envelope's status before you act on it.
- 4
Or send them there and back
No frame? Redirect the signer to
urlor open it in a new tab. When they finish, SignMaster sends them to your return_url with an event.# Your server answers the signer's "Sign now" click with a redirect:HTTP/1.1 303 See OtherLocation: https://www.usesignmaster.app/embed/9Lr2…https://app.example.com/signed?order=1042&event=signing_complete
- signing_complete
- They signed. Others may still have to; the envelope's status says.
- declined
- They declined to sign.
- link_used
- That link was already opened. Create a new session.
- session_expired
- The link wasn't opened within 5 minutes. Create a new session.
Anyone can type a URL, so treat the event as a hint. Check the envelope's status before you act on it.
05
Check an envelope
The envelope's status, each recipient's progress, and whether the signed PDF is ready. Needs envelopes:read.
curl https://www.usesignmaster.app/api/v1/envelopes/ENVELOPE_ID \ -H "Authorization: Bearer $SIGNMASTER_API_KEY"Response · 200
{
"envelope_id": "ce53b309-da39-4130-b663-ce9981cb7f4c",
"title": "Roof replacement agreement",
"status": "completed",
"sent_at": "2026-10-11T16:08:52.809901+00:00",
"completed_at": "2026-10-11T16:09:16.029572+00:00",
"created_at": "2026-10-11T16:08:52.688218+00:00",
"recipients": [
{
"name": "Dana Lee",
"email": "dana@example.com",
"type": "signer",
"status": "completed",
"completed_at": "2026-10-11T16:09:15.830521+00:00"
}
],
"final_pdf": {
"available": true,
"sha256": "dbdfd290dc0862616e0f7e137a5476ff116d964f779b67873b218216a4d75c8f"
}
}- status
- One of
draft,sent,in_progress,completed,declined,expired,voided. - recipients[].status
- Each recipient's progress, such as sent, viewed, completed or declined.
- final_pdf.sha256
- The SHA-256 fingerprint of the signed PDF, certificate included. Download the PDF in SignMaster; the fingerprint proves a copy is the sealed one.
06
Read what signers entered
One entry per field, with its label, page, signer and value. Needs envelopes:read.
curl https://www.usesignmaster.app/api/v1/envelopes/ENVELOPE_ID/data \ -H "Authorization: Bearer $SIGNMASTER_API_KEY"Response · 200
{
"envelope_id": "ce53b309-da39-4130-b663-ce9981cb7f4c",
"title": "Roof replacement agreement",
"status": "completed",
"fields": [
{
"field_id": "7f7c265a-c0bf-4c22-9d50-a52637c7e87e",
"file": "Roof replacement agreement.pdf",
"page": 1,
"label": "Signature",
"type": "signature",
"recipient": { "name": "Dana Lee", "email": "dana@example.com" },
"value": "[signature]",
"filled_at": "2026-10-11T16:09:15.830Z"
},
{
"field_id": "d952e52e-0170-4e14-b67c-649cd4958bc2",
"file": "Roof replacement agreement.pdf",
"page": 1,
"label": "Date signed",
"type": "date_signed",
"recipient": { "name": "Dana Lee", "email": "dana@example.com" },
"value": "2026-10-11T16:09:15.830Z",
"filled_at": "2026-10-11T16:09:15.830Z"
}
]
}Signatures read [signature]; the image never leaves SignMaster. Each read is noted in the envelope's history.
07
Errors and limits
Errors come back as JSON with a sentence you can show or log. Signing-link errors add a code to branch on.
{ "error": "This API key lacks the embedded:create scope." }{ "error": "There's no signer with that id or email on this envelope.", "code": "recipient_not_found"}- 200
- OK. 201 when a signing session was created.
- 400
- The request body is wrong: invalid JSON, a missing field, a bad return_url.
- 401
- No key, a malformed Authorization header, or a revoked or unknown key.
- 403
- The key lacks the permission, or the workspace's plan doesn't include the API.
- 404
- Not found in this workspace. Another workspace's envelope is a 404 too.
- 409
- The envelope or signer can't be signed right now. See the code.
- 429
- More than 60 requests in a minute with this key. Wait for the next minute.
Signing-link codes
- invalid_return_url · 400
- return_url isn't an absolute https URL (http only for localhost).
- invalid_frame_origin · 400
- frame_origin isn't a bare origin (scheme and host, no path).
- origin_not_allowed · 400
- The site in return_url or frame_origin isn't in Allowed origins.
- envelope_not_found · 404
- No envelope with that ID in this workspace.
- recipient_not_found · 404
- No signer with that email or ID on the envelope.
- envelope_not_sent · 409
- The envelope is still a draft. Send it first.
- not_their_turn · 409
- An earlier signer hasn't finished yet.
- envelope_not_signable · 409
- It's completed, voided, declined or expired.
60 requests a minute
Per key. Past that you get a 429 until the minute is up.
Crew and Company
On other plans keys answer 403. They start working again after an upgrade.
Your first signing link, today.
Create a key, allow your site, and send a signer from your own app. Questions about the API? We'll help.
