SignEnvoy docs
Sign in Start in the sandbox

Get started

Quickstart

Six commands, plain POSIX shell with curl and python3. The dashboard's API keys page shows these same steps with your key filled in, and CI runs them against a live server before every merge.

Before you start

Your workspace already has a test key. Open Settings, API keys: the keys table shows it shortened, so use its Copy key button (the quickstart on that page also has it filled in). Then type this line in your terminal, with your key in place of the dots:

export SENV_API_KEY=...

It prints nothing. export keeps the key in a shell variable named SENV_API_KEY for as long as this terminal window is open, and every command below reads it as $SENV_API_KEY. In a new window, run the line again.

Keys come in two modes. A senv_test_ key is the right one for a first run: it is never counted or billed, and the sealed PDF carries a watermark. Mail to your own workspace's members is delivered, marked as a test, so you can sign it from your inbox; everyone else's is captured in the dashboard instead of sent. A senv_live_ key sends real email, and each envelope is billed when everyone has signed it. The mode is part of the key, not a request flag.

  1. Grab the sample document
    curl -s --fail-with-body https://app-staging.signenvoy.com/static/sample-agreement.pdf -o sample.pdf
  2. Create an envelope with the PDF
    DOC=$(curl -s --fail-with-body -X POST https://app-staging.signenvoy.com/v1/documents \
      -H "Authorization: Bearer $SENV_API_KEY" \
      -F 'document={"title": "Quickstart agreement", "recipients": [{"name": "Ada Lovelace", "email": "ada@example.com"}], "fields": [{"type": "signature", "recipient_index": 0, "page": 1, "x": 0.1, "y": 0.8, "w": 0.35, "h": 0.07}]};type=application/json' \
      -F file=@sample.pdf \
      | python3 -c "import sys, json; d = json.load(sys.stdin); print(d['id']) if 'id' in d else sys.exit('error: ' + str(d.get('title', d)) + '  see ' + str(d.get('docs_url', '')))")
  3. Send it
    curl -s --fail-with-body -X POST https://app-staging.signenvoy.com/v1/documents/$DOC/send -H "Authorization: Bearer $SENV_API_KEY" -H "Content-Type: application/json" -d '{}'
  4. Sign it: Ada is not a member of your workspace, so a test key captures her mail instead of sending it. Open Settings, Test mode and click Open signing link (if you put your own address in step 2, the link is in your inbox). Then read it back: status is completed
    curl -s --fail-with-body https://app-staging.signenvoy.com/v1/documents/$DOC -H "Authorization: Bearer $SENV_API_KEY"
  5. Download the sealed PDF, a few seconds after signing. If it prints not-ready, sealing has not finished: wait a few seconds and run it again
    curl -s --fail-with-body -L -o signed.pdf "https://app-staging.signenvoy.com/v1/documents/$DOC/download?variant=signed" -H "Authorization: Bearer $SENV_API_KEY" \
      || { cat signed.pdf >&2; echo >&2; rm -f signed.pdf; false; }
  6. Next time, get told instead of checking: add a webhook endpoint (set WEBHOOK_URL to your https URL; the secret is shown once)
    curl -s --fail-with-body -X POST https://app-staging.signenvoy.com/v1/webhooks \
      -H "Authorization: Bearer $SENV_API_KEY" -H "Content-Type: application/json" \
      -d "{\"url\": \"${WEBHOOK_URL:?set WEBHOOK_URL to your https endpoint}\", \"events\": [\"document.completed\", \"document.sealed\"]}"

What happened

Step 2 created a draft in one call: the document's JSON and the PDF travel together as a multipart/form-data request (-F), a document part and a file part, and the answer is the draft with its id. That call checks the PDF (not empty, a readable PDF, no password, at least one page, at most 50 MB) and every field against it: its page must exist and its rectangle must stay inside the page (x + w and y + h at most 1), or it answers 422 validation-failed naming the problem, and nothing is created. Step 3 sent it: the recipient receives a signing link (or, with a test key, the email lands under Settings, Test mode). Sign it, then run step 4: one read, straight after, shows status as completed. Once sealing finishes, a few seconds later, step 5 downloads the sealed copy with its Certificate of Completion as the last page. Each value the signer entered (signature, initials, date, text, checkbox) is stamped into that copy at its field. Before sealing finishes, the download answers not-ready.

Get told instead of checking

Step 4 is how you look. In your app, don't look on a timer: step 6 adds a webhook endpoint, and SignEnvoy calls it when an envelope is completed and again when the sealed PDF is ready. Set WEBHOOK_URL to an https URL your server answers; the response carries the signing secret, shown once. On localhost, senv webhook tail --forward http://localhost:3000/webhooks/signenvoy --secret YOUR_LOCAL_SECRET delivers the same events without a tunnel. Polling and webhooks covers the rules if you have to poll: every 30 seconds, ETag and If-None-Match, or ?wait=30.