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.

https://www.usesignmaster.app/api/v1
  1. POST/envelopes/ce53…/embedded-sessionsurl opens once, within 5 minutes201
  2. Signer signs inside your pagesigned
  3. Your page hears signmaster:completedmessage
  4. 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. 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. 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 as SIGNMASTER_API_KEY.

  3. 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://localhost works 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.

  1. 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. 2

    Create a session

    Name the signer by recipient_email (any capitalization) or recipient_id, say where they land when they finish, and, to show it in your page, that page's origin. Needs the embedded:create permission.

    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. 3

    Show it in your page

    Put url in a frame on the page you named as frame_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_origin can show the session. The browser refuses every other site, and a session made without frame_origincan't be framed anywhere.
    • 2.frame_origin must 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.origin is https://www.usesignmaster.app before you trust one.
    • 4.A message is a hint for your interface. Check the envelope's status before you act on it.
  4. 4

    Or send them there and back

    No frame? Redirect the signer to url or 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 bodies
{ "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.