Make your first API request
Three requests that prove the key works, plus what every error response means.
- Last updated
- 6 minute read
- API
The API is a JSON API at a single base path. The first two calls need nothing set up beyond a key; the third is the one most integrations are actually built for.
The base URL
Every documented endpoint sits under one base path:
https://api.usesigned.co.uk/api/v1The index is public and needs no key, so it is a useful connectivity check from wherever your integration will run:
curl https://api.usesigned.co.uk/api/v1/{
"product": "Signed",
"api_version": "1.0.0",
"base_path": "/api/v1",
"modules": [ /* one entry per module */ ]
}Tip: The machine-readable specification lives at GET /api/v1/openapi.json. Point a generator at it and you have a typed client in a minute.
Authenticating
Send your key in the X-API-Key header on every request that is not the index or the specification.
curl https://api.usesigned.co.uk/api/v1/organisation \
-H "X-API-Key: $SIGNED_API_KEY"- Keys start with
sgn_. If you are pasting something else, it is the wrong credential. - Never put the key in a query string. Query strings end up in logs.
- Keep it in an environment variable or a secret store, and read it at start-up rather than on every call.
The request most integrations want
If mail flows through a relay, gateway or mail flow rule, hand Signed the body and take it back signed. That is what the stamp endpoint is for.
curl -X POST https://api.usesigned.co.uk/api/v1/signature/stamp \
-H "X-API-Key: $SIGNED_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sender_email": "amelia.hart@haldenrowe.co.uk",
"html_body": "<html><body><p>Thanks for your time.</p></body></html>"
}'{
"modified": true,
"html_body": "<html><body><p>Thanks for your time.</p>\n<!-- signed-stamped -->…</body></html>",
"signature_meta": { "template_id": "b8e0f1a2-…", "template_version": 5 }
}- Stamped bodies are idempotent. A body that already carries the marker comes back with
modified: false, so a rule that runs twice cannot double-sign a message. - No signature is not an error. If nobody matches the sender, you get
modified: falseand the body back untouched. - The signature is inserted before `</body>` when there is one, and appended otherwise.
What the errors mean
Every failure returns { error, reason }, where error is for a person to read and reason is for your code to branch on.
| Status | Reason | What it means |
|---|---|---|
| 401 | missing_api_key | No X-API-Key header |
| 401 | invalid_api_key | The key is wrong, or its organisation is gone |
| 401 | revoked_api_key | The key was revoked. Issue a new one |
| 401 | expired_api_key | The key passed its expiry date |
| 403 | ip_not_allowed | The request came from outside the key's allow-list |
| 403 | insufficient_scope | The key is missing the scope this endpoint needs |
| 402 | subscription_required | Writes are paused because the plan lapsed. Reads still work |
| 402 | upgrade_required | The endpoint needs a plan feature you do not have |
| 402 | suspended | The organisation is suspended. Contact support |
| 429 | rate_limited | Over the key's per-minute or per-day limit. Honour Retry-After |
| 404 | not_found | The record does not exist, or belongs to another organisation |
Note: Signed scopes every request to the organisation the key belongs to. There is no way to reach another organisation's data with a key, whatever ids you send.
Related articles
- Create and manage API keysOne key per system, the narrowest scopes that work, and a rotation plan you have actually written down.
- What the API coversTen modules, and the two ways signatures actually reach a message.
- A signature is not showingWork down this list in order. It separates the four or five causes that account for almost every case.
Something here out of date, or a step that did not work? Tell us and we will fix the article. Every page is checked against the running product, so corrections are welcome.