Skip to content
Browse the knowledgebase

API and integrations

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/v1

The 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: false and 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.

Failure reasons and what to do about them
StatusReasonWhat it means
401missing_api_keyNo X-API-Key header
401invalid_api_keyThe key is wrong, or its organisation is gone
401revoked_api_keyThe key was revoked. Issue a new one
401expired_api_keyThe key passed its expiry date
403ip_not_allowedThe request came from outside the key's allow-list
403insufficient_scopeThe key is missing the scope this endpoint needs
402subscription_requiredWrites are paused because the plan lapsed. Reads still work
402upgrade_requiredThe endpoint needs a plan feature you do not have
402suspendedThe organisation is suspended. Contact support
429rate_limitedOver the key's per-minute or per-day limit. Honour Retry-After
404not_foundThe 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.

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.