Cookbook
Sign with a human
Generate a signing session URL and route it to a human approver via email or in-app.
Last updated
Generate a signing session URL and route it to a human approver via email or in-app.
Trigger
Any document, board consent, or approval where the signer is a human and they're using a browser.
Call sequence
1. Create the document
POST /v1/documents { entity, template, … }2. Issue a signing session
POST /v1/signing_sessions { document, signer: holder, redirect_url }3. Email or render the session URL.
// out-of-band: send the magic linkIdempotency
Signing session idempotent on `(document, signer)`. Returns the same URL until expiry.
Webhooks
| Event | Description |
|---|---|
document.signed | Signer completed. |
Errors
| Status | Code | Description |
|---|---|---|
410 | session_expired | Session lifetime exceeded. Re-issue. |
Related
The flow has three legal moving parts:
- ESRA consent — the signer must affirmatively agree to do business electronically before any signature is collected. Captured once per stakeholder and reused on every subsequent envelope.
- Signing envelope — the API resource that wraps one document, one or more signers, and the per-signer magic link. The envelope carries the disclosure packet and the audit trail.
- Signature record — once the signer completes the flow, Matter writes
a
signatures[]entry on theDocumentwithlegal_basis: "esra_consent"and the populatedconsent_record.
Capture ESRA consent
E-SIGN §7001(c) and UETA §5(b) both require an affirmative pre-signature disclosure: the signer agrees to receive records electronically, confirms hardware/software ability to retain them, and is told how to withdraw consent. Matter records this once per stakeholder.
curl -X POST https://api.mattermode.com/v1/consents/esra \
-H "Authorization: Bearer $MATTER_KEY" \
-H "Matter-Version: 2026-05-01" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"stakeholder_id": "stk_F0und3rCEO",
"captured_via": "web_checkbox",
"captured_at": "2026-04-26T14:02:11Z",
"ip_address": "203.0.113.42",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15",
"disclosure_version": "esra-2026-01"
}'The consent is durable. Subsequent envelopes for the same stakeholder skip
this step automatically — Matter validates the most recent active consent
at the time the envelope opens. If the consent has been withdrawn (POST /v1/consents/esra/{id}/withdraw), the next envelope returns 422 esra_consent_required.
Open the signing envelope
The envelope binds the document to one or more signers and renders the disclosure packet that the signer reads at the magic-link landing page.
curl -X POST https://api.mattermode.com/v1/signing_envelopes \
-H "Authorization: Bearer $MATTER_KEY" \
-H "Matter-Version: 2026-05-01" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"document_id": "doc_83b_2026Q2_F0und3rCEO",
"signers": [
{
"stakeholder_id": "stk_F0und3rCEO",
"role": "signer",
"delivery_email": "jane@waypoint.example"
}
],
"disclosure": {
"packet_version": "esra-2026-01",
"include_document_summary": true
},
"expires_in_days": 14
}'The response carries the envelope plus a per-signer signing_url. You can
either let Matter dispatch the magic link by email (default) or render the
URL inside your own UI by setting delivery.channel: "manual" on the
envelope.
POST /v1/signing_envelopes/{id}/send dispatches the magic link and flips
the envelope to sent. This is a separate call so you can preview, attach
exhibits, or hand off to a different delivery channel before the signer is
notified. The URL is single-use against a short-lived signing token (TTL
60 minutes; rotates on each open).
What lands on the document
After a successful run, Document.signatures[] looks like:
{
"signatures": [
{
"stakeholder_id": "stk_F0und3rCEO",
"signed_at": "2026-04-26T15:18:42Z",
"legal_basis": "esra_consent",
"method": "magic_link",
"intent_text": "Jane Smith",
"consent_record": {
"consent_id": "cnst_7M1qDvL",
"disclosure_version": "esra-2026-01",
"captured_at": "2026-04-26T14:02:11Z",
"ip_address": "203.0.113.42",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5)"
},
"signing_envelope_id": "sigen_3aFv7mYpQ2",
"signing_session_id": null,
"agent_authority": null,
"audit_entry_id": "aud_4Z9pKsRq"
}
]
}Three fields are load-bearing:
legal_basisisesra_consentbecause the signature was applied by a human reading the disclosure under the magic-link rail.consent_recordis the persisted snapshot of the ESRA consent that was active at signing time. Withdraw the consent later and this record is still preserved.signing_session_idisnullbecause the magic-link shape does not mint a signing session; the URL itself carries the bearer.
See legal basis reference for the full enum.
Failure modes
| Code | What happened | Recovery |
|---|---|---|
422 esra_consent_required | The signer has no active ESRA consent at envelope-open time. | Capture consent (above) and POST /v1/signing_envelopes/{id}/send again with the same Idempotency-Key. |
403 stakeholder_identity_unverified | The signer has not completed identity verification. | Run POST /v1/stakeholders/{id}/verify_identity, then resend. |
document.signature.declined | Signer clicked "decline" on the magic-link page. | The envelope status flips to declined. The data.reason field carries the signer's note. Issue a fresh envelope with the corrected document. |
signing_envelope.expired | expires_in_days elapsed without all signatures collected. | POST /v1/signing_envelopes/{id}/reopen mints fresh per-signer URLs and resets the expiry clock. |
410 signing_token_consumed | Signer attempted to reuse the magic link after signing. | Expected; no remediation needed. |
422 disclosure_changed_resign_required | Disclosure version was bumped between envelope open and signer landing. | Matter auto-rolls the envelope to the new disclosure and re-mints the URL. The signer receives a fresh email. |