Signing Worker Protocol
Signing Worker Protocol (SWP/1)
How SignatureAPI and a signing worker produce one qualified signature, the shape every request and response shares, and what SignatureAPI checks
Private beta. Qualified signatures are available on request. Request access and we enable them for your account. SWP/1 is in beta and may change.
The Signing Worker Protocol (SWP/1) is the contract between SignatureAPI and a signing worker. A worker serves four endpoints under its base URL:
| Endpoint | Purpose |
|---|---|
POST /v1/credential | Return the signer’s certificate chain |
POST /v1/authorize | Get the signer’s approval for exactly these digests |
POST /v1/sign | Return one signature per digest |
GET /v1/health | Report status and list the accounts the worker accepts |
Every POST is authenticated with a token that SignatureAPI signs for that one request.
Lifecycle of a signature
One signer’s turn to sign is a signing session. In a session, SignatureAPI calls the three operations in this order:
credential. Which certificate will this signer sign with?authorize. The signer approves signing exactly these digests.sign. Produce the signature values.
The order follows from how PDF signatures work. A PAdES signature (the standard format for signatures inside a PDF) embeds a hash of the signing certificate, so SignatureAPI needs the certificate before it can compute the digest. A qualified remote signature binds the signer’s approval to the exact digests, so the digests are final before authorize.
Each operation answers completed, pending or failed. A pending answer means the signer must do something at the provider first, such as identify or approve. See Pending steps.
sequenceDiagram
participant B as Signer's browser
participant P as SignatureAPI
participant W as Signing worker
participant T as Trust service provider
B->>P: Finish the ceremony
P->>W: POST /v1/credential
W-->>P: pending (action_url)
P-->>B: Redirect to action_url
B->>T: Identify
T-->>B: Redirect to callback_url?code=...
B->>P: GET callback_url
P->>W: POST /v1/credential (callback.code)
W-->>P: completed (certificate chain)
Note over P: Compute the digest
P->>W: POST /v1/authorize (digests)
W-->>P: completed (authorization reference)
P->>W: POST /v1/sign
W->>T: Sign the digest
W-->>P: completed (signatures)
Note over P: Verify, then embed in the PDF
A worker that needs nothing from the signer answers completed three times in a row, and the browser never leaves the ceremony. If any step fails, the session fails, and the signer can retry from the ceremony in a new session.
Common request fields
Every POST body carries these fields, plus the operation’s own. Binary values are standard base64 with padding. Timestamps are RFC 3339.
{
"protocol": "swp/1",
"session": { "id": "sgs_YFobK1NDktAuz0wzplR4OP", "attempt": 1 },
"scheme": "eu_eidas",
"signer": {
"id": "re_00ZeZjRaXCgT30n1eBx53N",
"name": "Jane Doe",
"email": "jane.doe@example.com"
},
"callback_url": "https://api.signatureapi.com/v1/signing-sessions/callback?state=..."
}
| Field | Description |
|---|---|
protocol | Always swp/1. |
session.id | The signing session. Key anything you store by it. A retry from the ceremony starts a new session with a new ID. |
session.attempt | Starts at 1. Part of the Idempotency-Key. |
scheme | The legal framework of the signature. Always eu_eidas today. |
signer.id | The recipient ID. The token’s sub claim carries the same value. |
signer.name | The signer’s name, as set on the envelope. |
signer.email | The signer’s email address, or "" when the recipient has none. |
callback_url | Where you send the signer’s browser when an interactive step ends. Treat it as opaque. |
callback.code | Present only when the request resumes after a redirect. The single-use code your worker added to callback_url. |
The signer’s name and email are personal data. Log IDs, not request bodies.
Responses
Answer every operation with HTTP 200 and one of three bodies:
{ "status": "completed", ...result }
{ "status": "pending", "action_url": "https://signer.example.com/consent?ticket=...", "expires_at": "2026-08-24T16:45:00Z" }
{ "status": "failed", "error": "access_denied", "error_description": "The signer refused in the app", "retryable": false }
completedcarries the operation’s result, described on each endpoint page.pendingis allowed oncredentialandauthorizeonly. See Pending steps.failedcarries an error code.
Use a non-200 status only when you refuse the request itself.
What SignatureAPI checks
Before a signature reaches the deliverable, SignatureAPI runs three checks. If one fails, the session fails with that check’s name.
signature. The signature verifies over the exact digest SignatureAPI sent, with the public key of the signer certificate.chain. Every certificate in the chain was valid at signing time, and each one is signed by the next.scheme. The session’s scheme iseu_eidas.
SignatureAPI always verifies against the chain it saved when it computed the digest: the one from credential, or the connection’s static certificate. It never reads certificates from the sign response.
SignatureAPI does not check that the certificate is qualified. Making sure your worker signs with qualified certificates from a qualified provider is the worker owner’s responsibility.
Requirements at a glance
- Public HTTPS. Serve the worker on port 443 with a certificate from a public certificate authority. SignatureAPI connects only to public addresses.
- No redirects. Answer on the URL SignatureAPI called. SignatureAPI never follows a redirect.
- Verify every token, including the body hash against the raw bytes. See Authentication.
- Accept only listed accounts. List your accounts’ connection tokens in
/v1/healthand refuse tokens for any other account. - Single-use codes. Any
codeyou add tocallback_urlworks once. - Sign once. Never sign twice for one
Idempotency-Key. - Small responses. SignatureAPI rejects responses larger than 1 MiB.