How the API and webhooks work together
SignSwifly gives your own systems two ways to work with your envelopes. The API is how your system asks SignSwifly to do something, or to tell it something: send this lease, how far has it got, give me the signed copy. Webhooks are how SignSwifly tells your system that something has happened, as it happens: it was opened, signed, finished. Most connections use both. Both come with every paid plan, from Solo up.
This guide explains how they differ, how a system uses each, and how to try them both in test mode before writing any code. For a first envelope sent step by step, see Getting started with the API and webhooks. The API reference has every operation in detail.
The difference at a glance
| The API | Webhooks | |
|---|---|---|
| Who starts it | Your system, whenever it needs to. | SignSwifly, as soon as something happens. |
| Which way it goes | Your system calls https://anz.signswifly.com.au/api/v1. | SignSwifly calls an HTTPS address of yours, your endpoint. |
| What it’s for | Doing and reading: send, remind, resend, void, check progress, download the signed documents. | Hearing what happened: sent, viewed, signed, completed, declined, expired, voided, or an email that bounced. |
| What it carries | Whatever you asked for: an envelope, a list, a PDF. | A short JSON message naming the envelope and, where there is one, the recipient. Never the documents. |
| How each side knows who’s talking | Your request carries an API key (ssk_live_…, or ssk_test_… in test mode), which SignSwifly checks. | Each delivery carries a signature made with your endpoint’s signing secret (whsec_…), which your system checks. |
| What you set up | A key, under Settings → API & webhooks, with the scopes it needs. | An endpoint, under Settings → API & webhooks: a public HTTPS address that answers within 10 seconds. |
| If it doesn’t get through | Your system tries again, with the same Idempotency-Key, so nothing happens twice. | SignSwifly tries again for about three days, so a delivery can arrive more than once. |
| Limits | 600 requests a minute for each key. | 10 endpoints for each workspace. |
| Where to look afterwards | The envelope’s audit trail, which names the key. | The endpoint’s delivery log, for 30 days. |
Which to use for what
- Use the API when your system decides something should happen: a deal reaches the contract stage, so it sends the contract; a signer says the email never came, so it resends.
- Use webhooks when your system needs to know something happened: a contract is signed, so the deal moves on and the signed copy is filed.
- Prefer a webhook to asking again and again. Checking every few minutes whether an envelope is finished works, but it’s late by however long you wait between checks, and spends requests on answers that haven’t changed. A webhook usually arrives within seconds.
- A webhook says what happened; the API acts on it.
envelope.completedtells your system an envelope is finished. To get its signed documents, your system then asks the API for them. - Keep the API as the record. A webhook can arrive late, twice or out of order, and nothing is sent to an endpoint while it’s switched off. Once a day, say, read your envelopes with
GET /api/v1/envelopesto catch anything a webhook didn’t bring.
An example: a lease sent from your CRM
| Step | Who starts it | What happens |
|---|---|---|
| 1 | Your system, with the API | It sends the lease from a template: POST /api/v1/envelopes/from-template with "send": true and an Idempotency-Key. The answer has the envelope’s id, which your system keeps beside the deal. |
| 2 | SignSwifly, with a webhook | envelope.sent: your CRM shows the lease as out for signature. |
| 3 | SignSwifly, with a webhook | recipient.viewed, then recipient.signed, for each signer as they go. |
| 4 | SignSwifly, with a webhook | envelope.completed: everyone has signed and the documents are sealed. |
| 5 | Your system, with the API | GET /api/v1/envelopes/{id} lists its documents. GET /api/v1/envelopes/{id}/documents/{documentId}/sealed and GET /api/v1/envelopes/{id}/certificate download the signed lease and its certificate of completion, to file against the deal. |
| 6 | Your system | If envelope.declined, envelope.expired or envelope.voided arrives instead, it stops waiting, and can send a new envelope with the API. |
Calling the API
- Every request goes to
https://anz.signswifly.com.au/api/v1over HTTPS, with the key in theAuthorizationheader. Requests and answers are JSON, except downloads, which are PDF files. - A key does only what its scopes allow. A request outside them is refused with a
403and the codemissing_scope. - An error comes back as problem details: a
detailwritten for whoever is fixing it, acodefor your system to act on, and atraceIdto quote to support. - Creating or sending an envelope takes an
Idempotency-Keyheader: a new UUID for each envelope. Repeat a request after a timeout with the same key, within 24 hours, and you get the first answer back, with nothing sent twice. - Lists come a page at a time:
data,hasMoreandnextCursor. PassnextCursorback as?cursor=for the next page;limitis 1 to 100, and 25 if you don’t say. - A key can make 600 requests a minute. Past that, a
429says in itsRetry-Afterheader how many seconds to wait. - Keep keys on your servers, never in a web page or an app people download.
For example, the envelopes finished most recently:
curl "https://anz.signswifly.com.au/api/v1/envelopes?status=completed&limit=10" \
-H "Authorization: Bearer ssk_live_…"
Receiving webhooks
- Your endpoint is a public HTTPS address that accepts a
POSTof JSON. Add it under Settings → API & webhooks with + Add endpoint, and choose the events it should hear about. - Before acting on a delivery, check its
SignSwifly-Signatureheader against the raw body, as Check each delivery came from SignSwifly describes. The API reference has the check as ready-to-use code in C# and JavaScript. Anyone can post to your address; only SignSwifly can sign. - Answer with any
2xxstatus within 10 seconds, then do the work, from a queue, say. Anything else is tried again later. - Skip a delivery whose
idyou’ve already handled, and usecreatedAt, not the order they arrive in, to tell which happened first. - For anything the message doesn’t carry, such as the signed documents, call the API.
A delivery when someone signs:
{
"id": "evt_4f0c…",
"type": "recipient.signed",
"createdAt": "2026-09-29T01:02:03Z",
"apiVersion": "v1",
"workspaceId": "…",
"test": false,
"data": {
"envelope": { "id": "…", "subject": "Lease", "status": "sent", "createdAt": "…", "sentAt": "…" },
"recipient": { "id": "…", "name": "Jane Citizen", "email": "jane@example.com", "role": "signer",
"status": "signed", "routingOrder": 1 }
}
}
Send test event, beside an endpoint, sends one with no envelope, once and without retries:
{
"id": "evt_…",
"type": "webhook.test",
"createdAt": "…",
"apiVersion": "v1",
"workspaceId": "…",
"test": false,
"data": { "message": "A test event from SignSwifly. If you can read this, your endpoint works." }
}
test is true for a test envelope’s events, and for the test event sent to a test endpoint: see Try it yourself.
Try it yourself
Test mode lets you try both without sending anything real. A test key (ssk_test_…) works as a live key does, with the same operations, scopes, limits and answers, but every envelope it makes is a test envelope:
- It goes only to people in your team: the email addresses your workspace’s members sign in with.
- It says TEST in Send & Sign, at the top of every email (with
[TEST]in the subject) and on the signing page. - It doesn’t use your plan’s envelopes, drafts or email allowance. Up to 50 can be sent a day.
- Nobody is texted, and nobody is left for a signer to name, such as a nominee or a witness the signer names.
- Once it’s completed, its documents and certificate have TEST across every page and no seal. SignSwifly hasn’t signed them, and they have no legal effect.
- It’s deleted, documents and all, 7 days after it was made, whatever state it’s in.
A test key sees only test envelopes, and a live key only real ones. Webhooks keep to the same line: a test endpoint hears about test envelopes only, and a live endpoint about real envelopes only, so your real system never acts on a test. Every delivery says which, in test. Test mode comes with the API, on Solo, Team and Scale.
1. Make a test key
Under Settings → API & webhooks, choose + New API key, then Test. Name it “Trying the API”, set it to expire in 30 days, and keep the four scopes that start ticked. Tick webhooks:manage too if you’d like to try adding endpoints through the API.
2. Try the API in the console
The API console runs every operation from your browser. Paste your test key, pick an operation, fill in its boxes and choose Send. It shows the answer, offers the ids in it for the next operation, and gives the same request as curl. It keeps your key only while the page is open, and asks before a live key changes anything.
GET /api/v1/mesays the key works, who it acts as, and"test": true.GET /api/v1/templateslists your active templates, andGET /api/v1/templates/{id}gives a template’s roles and variables.POST /api/v1/envelopes/from-templatewith yourself in each role and"send": truesends you a test envelope. Leave"send"out to make a draft instead.
Prefer an API tool? The Postman collection has the same steps in order, with your key in one variable and each request saving the ids the next one needs. Or import https://anz.signswifly.com.au/openapi/api-v1.json, which describes the whole API, into Postman, Insomnia or Bruno.
3. Watch webhooks arrive
A request-inspection service, such as webhook.site, gives you a temporary HTTPS address and shows every request sent to it. Add that address as an endpoint, choose Test and every event, then choose Send test event. Within seconds the service shows the delivery: its JSON, and the SignSwifly-Signature, SignSwifly-Event-Id and SignSwifly-Event-Type headers. The endpoint’s Delivery log shows the same delivery from SignSwifly’s side, with what the service answered.
Such a service is someone else’s, and keeps what it receives, names and email addresses included. Use one only for test envelopes to yourself, and remove the endpoint when you’ve finished.
4. Follow an envelope from start to finish
Open the [TEST] email, view the document and sign it, and watch envelope.sent, recipient.viewed, recipient.signed and envelope.completed arrive at your test endpoint. Then download the signed copy with the API, as in step 5 of the example: it has TEST across every page.
5. Run the sample integration
The Python sample is a small integration in one file, with nothing to install: it sends an envelope from a template, listens for webhooks, checks each one’s signature, skips repeats, and downloads the signed documents when an envelope is completed. Its README says how to run it with a test key, and how to receive webhooks on your own computer through a tunnel.
6. Go live
Make a live key, and a live endpoint with its own signing secret, and put them in place of the test ones. Nothing else in your code changes. From then on envelopes go to anyone, are sealed, and count towards your plan like those you send from the app.
7. Tidy up
- Remove any endpoint at a request-inspection service.
- Delete the test key once you’re done with it, or let it expire.
- Test envelopes delete themselves 7 days after they were made, so there’s nothing to delete.
Next steps
- Getting started with the API and webhooks: keys and scopes, a first envelope, setting up and checking webhooks, failed deliveries, limits, and what a change of plan does.
- The API reference: every operation, error code and webhook event, with code to check deliveries.
- The API console, the Postman collection and the Python sample, to try it all with a test key.