Getting started
The API does one thing: it puts a document in front of somebody and proves who signed it. You raise a document with one call and learn the outcome from a webhook. Everything in between — the photo ID, the camera check, the emails — happens on our side.
| Gamma | https://api-gamma.thegentlemanagreement.com | Test environment. Nothing here is a real signature. |
|---|---|---|
| Signer client | https://gamma.thegentlemanagreement.com | Where a signer is sent. There is no API for signing on somebody's behalf. |
There is no sandbox mode on a production key. Use gamma, whose data is disposable and whose evidence bucket is not under a compliance lock.
Accounts and approval
Anyone can create an account at the console and start raising documents immediately. Nothing reaches the outside world until a person here has approved the account.
This is not a formality. An unapproved account that could email strangers would be a way to send mail from our domain, with our sending reputation, to any address it chose — a phishing kit with a signature ceremony attached. So the gate is on delivery and visibility, not on the API.
What a pending account can and cannot do
| While pending | Once approved |
|---|---|
| Create documents through the API | Same |
| Buy credits and subscribe | Same |
| No invitation email reaches a signer | Invitations are delivered |
| No signed or completed PDF is emailed to anyone | Both are delivered to every party |
| Signers cannot see or open the document at all | Everyone in the thread can |
| No API key is issued | Keys can be issued and revoked |
Held mail is kept, not dropped. Approval releases everything written while the account was waiting, in the order it was written, with fresh download links — a presigned URL minted a week earlier would arrive expired. The signer's first sight of the document is an ordinary invitation rather than one that never came.
A signer asking for a document from an unapproved owner is told it does not exist, in the same words an imaginary document gets. Saying "pending approval" would confirm to a stranger that this address was sent something, and by whom.
Signing up
POST /owners/signup | email, organisationName, password. The organisation name is what signers read: "X has asked you to sign". |
POST /owners/verify-email | email, code. Returns a console session. |
POST /owners/login | Email and password. An address that is not an owner fails exactly like a wrong password. |
POST /owners/me/proof | A photograph of a licence or a utility bill showing name and address. We read the text and keep that; the image is deleted after 30 days, like a signer's. |
GET /owners/me | Status, plan, credit balance, and whether proof has been sent. |
PUT /owners/me | name and webhookUrl. The URL must be https: the events carry hashes of signed documents. |
GET /owners/me/documents | Everything you raised, each party, and who has signed. |
POST /owners/me/api-keys | Issues a key, once approved. Shown once — only a hash is stored. |
DELETE /owners/me/api-keys/{keyId} | Revokes it immediately. |
POST /owners/me/billing/checkout | Stripe checkout for credits or a plan. Allowed while pending. |
Authentication
Five kinds of caller, five credentials, and they are not interchangeable.
| Caller | Credential | Reaches |
|---|---|---|
| You, the document owner | x-api-key | Raising documents, templates, billing |
| A signer | Authorization: Bearer, minted after an identity check | Their own documents only |
| An account holder | Authorization: Bearer, console session | Their own account, keys, documents and billing |
| Somebody reading later | Authorization: Bearer, reader token from a password | Documents they already signed — never signing |
| An operator | Authorization: Bearer, operator token | The review queues, for accounts and for identity checks |
An API key is unique to one account, is shown once when issued, and is stored as a hash — a lost key is replaced, never recovered. Revoking one takes effect on the next request.
An API key identifies an owner and nothing else. It cannot sign, cannot read a signer's other documents, and cannot see an identity photograph — those are deleted on a schedule we do not let callers change.
Raising a document
POST /documents
Send one of three sources. Exactly one.
| Field | Type | Meaning |
|---|---|---|
title | string | What the signer sees in their list and in the subject line. |
signerEmails | string[] | Everyone who must sign. Each signs separately and each is verified separately. |
pdf | string, base64 | A finished PDF. Under 4.5 MB. |
markdown | string | Rendered by us. Simpler than shipping a PDF, and the source is kept with the evidence. |
templateId | string | An approved template, filled with values. |
requiresFreshCheck | boolean | Ignore any cached verification and make this signer prove identity again today. |
curl -X POST https://api-gamma.thegentlemanagreement.com/documents \
-H "x-api-key: $TGA_API_KEY" \
-H "content-type: application/json" \
-d '{
"title": "Coaching agreement 2026",
"signerEmails": ["alex@example.com"],
"pdf": "JVBERi0xLjQKJ...",
"requiresFreshCheck": false
}'
{
"documentId": "doc_9f3c...",
"status": "open",
"billable": true,
"billingReason": "standard"
}
201, and the signer has an email. billable is decided at this
moment and does not change afterwards: a signer already verified this calendar month costs
nothing extra, whatever happens next.
Several signers
Each party signs the version the previous one produced, so the chain of sealed copies is the record of what each person actually read. There is no "send to all at once" that hides this.
Templates
A template is markdown with {{placeholders}}, versioned and approved before use.
Raising from an unapproved version is refused — a document nobody signed off is not a
document you want in evidence.
GET /templates | List yours. |
POST /templates | Create one. |
PUT /templates/{templateId} | New draft version. |
POST /templates/{id}/versions/{n}/preview | Render without raising anything. |
POST /templates/{id}/versions/{n}/approve | Make a version usable. |
Webhooks
Webhooks are how you learn anything. They are queued and retried with backoff, so an endpoint that is down for an hour loses nothing.
| Event | When |
|---|---|
document.signed | A party signed. Carries both hashes. |
document.completed | Every party has signed. |
verification.review | A signer's identity needs a human. Usually clears within a business day. |
Every delivery carries x-tga-signature, an HMAC-SHA256 of the raw body. Verify it
before acting, and compare in constant time. An unverified webhook is a stranger telling you a
contract was signed.
Evidence
GET /documents/{documentId}/evidence
What a dispute actually needs, and what a caller cannot alter:
presentedSha256— the bytes the signer read.sealedSha256— the bytes after their signature was written in.- The date they chose, and the true server time they confirmed it.
- The identity decision behind the signature, and which kind of document was shown.
Never the photographs and never the video. Those are deleted on a schedule, which is the point: what survives is proof that a check happened, not the biometrics that made it.
GET /ops/owners/{ownerId}/evidence exports everything
you own, including instructions for checking a hash without us. That export exists so leaving
is possible.
Billing
You pay per distinct signer per calendar month, never per document and never per seat. A signer is never charged.
| Plan | Price | Included |
|---|---|---|
| Prepaid credits | $1.00 per signer-month | Four documents for that signer |
| Small | $5 / month | 10 signer-months |
| Busier | $15 / month | 100 signer-months |
| Largest | $25 / month | 1000 signer-months, fair use above 150 new verifications |
A verification is cached for 36 months, so a returning signer costs us almost nothing and is
not billed again in the same month. GET /billing/balance
shows where you are.
Management
The management view at /ops.html is for the people running the platform. It
shows revenue by month, signatures billed against total, where the money comes from, and
every account with what its proof of identity said.
POST /ops/login | Email and password. The address must be on the list the environment was deployed with, and that is checked after the password so this cannot enumerate operators. |
GET /ops/reports/revenue | Twelve months of revenue and signature counts, read from the billing ledger. |
GET /ops/owners | Accounts waiting for review. |
POST /ops/owners/{ownerId}/decision | Approve or reject. Approving releases every message held while the account waited. |
POST /ops/owners/{ownerId}/block | Block or unblock a live account. |
Blocking is not deletion. It stops new mail, hides the account's documents from signers and revokes its API keys immediately. It does not touch anything already signed: a signature is evidence, and evidence does not stop being true because we fell out with the person who asked for it. Unblocking restores the account to approved; the revoked keys stay revoked, and reissuing one is a deliberate act.
Operator sign-in is an interim. The design calls for a Cognito pool with mandatory MFA and that is still the right answer; what exists today is a password held to the same rules as everybody else's, usable only from a server-side list, and claimable only with a secret held in Secrets Manager. It is written down here rather than left to be discovered.
Errors and limits
Errors are {"error": "a sentence"}. The status carries the meaning.
| Status | Means |
|---|---|
400 | The request is wrong. Repeating it unchanged will not help. |
401 | No credential, or one we do not recognise. |
403 | A valid credential of the wrong kind. |
409 | Already done. Signing is idempotent on x-idempotency-key. |
429 | Rate limited. Identity calls cost us real money, so they are limited per email, per IP and per day. |
502 | Something we depend on failed. You did nothing wrong; retry. |
A request body is capped at about 4.5 MB, which is an API Gateway limit rather than a policy.
What the signer does
Nothing to install, and no account.
- Photograph a driver's licence or passport.
- A short camera check, matched against the photo on the ID.
- A six-digit code to their email, which is what ties the identity to the address you gave us.
- Read, type their name, confirm.
No camera on their computer? The page offers a QR code that carries the whole check to their phone and hands the thread back when it is done. There is no weaker path: if the identity check cannot run, no signature is collected.
After signing, a signer can set a password and come back to read what they signed. That password mints a reader token and nothing more: it opens documents already signed and is refused by the signing route. A password proves somebody knows a secret, which is exactly the evidence this product exists to replace — so signing always means an ID and a live face, every time.
Signers must be 18 or over. A parent or guardian signs for a minor, and the record says so.