Skip to main content

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.

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.

If your egress address is not static — most container platforms, most CI runners — put a NAT gateway or a fixed-address egress proxy in front of the calls you want to allow-list, rather than widening the list to a range you do not control.

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.