Authentication
Every request must carry a valid API key. We accept both header conventions so that an existing Anthropic integration authenticates without modification.
Both header styles are accepted
Send your key either as an Authorization: Bearer token or in an x-api-key header.
They are equivalent. If both are present, Authorization wins.
curl https://ai.dijitul.uk/v1/messages \
-H "authorization: Bearer $GATEWAY_API_KEY" \
-H "content-type: application/json" \
-d '{"model":"claude-sonnet-4-6","max_tokens":64,"messages":[{"role":"user","content":"ping"}]}'
The official Anthropic SDKs send x-api-key, which is why setting api_key and
base_url is all you need to do.
Key format
dj_live_7Qx4mA2vRkP9dLbT1yWnZsHf3jCgEu6V
└┬┘ └─┬┘ └──────────────┬───────────────┘
│ │ └── 32 characters, CSPRNG
│ └────────────────── environment: live or test
└─────────────────────── issuer prefix
The issuer prefix exists so that a leaked key is recognisable. Secret scanners, log redaction rules and
code review all benefit from a credential that announces what it is. You can safely add
dj_live_ to your own scanning patterns.
Shown once
We store a SHA-256 hash of the key, plus the first few characters for display. We cannot show you a key again after creation and we cannot recover one. If it is lost, revoke it and issue a replacement.Test and live keys
| Environment | Prefix | Behaviour |
|---|---|---|
| Live | dj_live_ |
Real inference. Metered against your allowance and billed. |
| Test | dj_test_ |
Deterministic stub responses with realistic shapes, including streaming events and error cases. Not billed, and never reaches a model. |
Test keys are useful in CI: your integration tests exercise the full request and response path — including SSE parsing and error handling — without spending tokens or sending anything to an inference platform.
What a key carries
Configuration is attached to the key, not to the account, so that different applications can have different privileges under one billing relationship.
residency
uk | eu
The residency tier. Cannot exceed the tier your plan permits. Enforced fail-closed: a request that cannot be served within the tier is refused, never widened.
privacy_mode
off | flag | redact | tokenise
The PII handling applied before the request leaves the gateway. See privacy modes.
allowed_models
array | null
Restrict this key to named model aliases. null means every model the plan and
residency tier permit.
allowed_ips
array | null
Source addresses or CIDR ranges permitted to use this key. null means no
restriction.
expires_at
timestamp | null
The key stops working at this instant with no further action required.
Rotation
Keys do not expire unless you give them an expiry, but rotating them periodically limits the value of an old leak. Rotation is deliberately overlap-friendly:
# 1. Create the replacement key in the dashboard, or via the CLI.
# 2. Deploy it. Both keys are valid at this point.
# 3. Confirm no traffic on the old key (dashboard → API keys → last used).
# 4. Revoke the old key.
# There is no window in which neither key works.
The dashboard records when each key was last used, so you can confirm a key is genuinely idle before revoking it. Revocation takes effect immediately, including for requests already in flight.
IP allow-listing
An allow-list turns a stolen key into a much smaller problem. Individual addresses and CIDR ranges are both accepted, IPv4 and IPv6:
{
"name": "invoice-summariser (production)",
"allowed_ips": [
"203.0.113.24/32",
"198.51.100.0/28"
],
"expires_at": "2027-01-31T00:00:00Z"
}
The check runs before the request is forwarded upstream, so a blocked request consumes no allowance. A
request from outside the list returns permission_error — deliberately the same response an
unauthorised key would get, so probing tells an attacker nothing.
Authentication failures
{
"type": "error",
"error": {
"type": "authentication_error",
"message": "No valid API key provided. Send it as 'Authorization: Bearer <key>' or 'x-api-key: <key>'."
}
}
| Status | Type | Cause |
|---|---|---|
401 |
authentication_error |
Missing, malformed, revoked or expired key. |
403 |
permission_error |
Valid key, but not permitted — source IP not allow-listed, or model not permitted for this key. |
403 |
residency_unavailable |
Valid key, but the requested model has no route inside the key's residency tier. |
Full catalogue on the errors page.
Good practice
- One key per application and environment. Revoking staging should never take production down.
- Never put a key in client-side code, a mobile binary, or a public repository. Anything shipped to a user's device is not a secret.
- Give keys an expiry, especially keys issued to contractors or for a time-boxed project.
- Allow-list production egress addresses.
- Use a test key in CI so a broken test loop cannot spend your allowance.
- Add
dj_live_to your pre-commit secret-scanning rules.