Security
Most of this is the platform's job. This page covers what it does on your behalf, and the short list of things only you can do.
Your responsibilities
- Keep secrets in a secret manager, never in the repository or a committed env file.
- Grant the smallest set of scopes the integration actually uses.
- Call the API from your server. Never ship a live key to a browser or a mobile binary.
- Verify webhook signatures, including the timestamp.
- Rotate on a schedule, and immediately after any suspicion of exposure.
Everything below is what happens whether you think about it or not.
Key storage
Only a hash of the secret is stored. Nobody can read a key back — not you, not support, not an attacker who reaches the database. Lookups happen by the public key id, and the secret is compared in constant time so timing cannot leak it.
Lists and reads show a masked form (agy_test_9fK2…_••••bN7k), never the
secret. The plaintext is returned exactly once, at create or rotate.
Scope enforcement
Scopes are checked on every request, and the check fails closed: a request that somehow arrives without a resolved key is rejected rather than waved through.
Scopes cannot be changed after a key is minted. A compromised key cannot be widened, by you or by whoever holds it — you mint a new one and revoke the old.
Because scopes are immutable and enforced per route, the damage from a leaked key is exactly what you granted it. A read-only analytics key is a read-only incident.
See Scopes.
Tenant isolation
Every read and write is scoped to the account that owns the key. There is no
parameter that widens that, and X-Account-Id is rejected when it disagrees
with the key rather than being honoured.
A resource belonging to another account returns 404, not 403. Answering
403 would confirm the id exists and let someone enumerate identifiers by
probing.
Rotation with an overlap
Rotation issues a new secret and keeps the previous one valid for 24 hours, so a rolling deploy never has a window where half your fleet is unauthorised.
Webhook secrets rotate the same way, and during the window deliveries are signed with both — provided your verifier checks every signature in the header. See Webhooks.
Revocation
Revocation takes effect immediately, not at the next cache expiry. A revoked key cannot be un-revoked; mint a replacement.
You can revoke the calling key from the API itself, which makes a kill switch easy to build into your own tooling:
curl -X DELETE https://api.agentency.com/v1/api_keys/1 \
-H "Authorization: Bearer <YOUR_KEY>"A key may only revoke itself. Managing other keys is a dashboard action behind a human login.
Outbound request safety
Two features let you point the platform at a URL: webhook endpoints and crawlers. Both are validated before anything is fetched, and internal addresses, private ranges, cloud metadata endpoints and this API's own host are refused.
Webhook deliveries additionally pin the resolved address, so a hostname that passes validation and then resolves somewhere private cannot be used to reach inside the network. Redirects are not followed, and response bodies are read only up to a small cap.
What is never logged
- API key secrets, in any form.
- Webhook signing secrets.
- Request bodies on the public API. The request log records the method, the
route pattern (
/v1/customers/{id}, not the id), the status, the duration, and the error code. - Provider error text from an action, which is redacted before it is stored so a failing upstream cannot leak a token into your run records.
Server errors never include a stack trace, a query, a provider response body,
or a file path — only SERVER_ERROR and a request_id.
IP allowlists
A key can be pinned to specific addresses or CIDR ranges; requests from anywhere else are rejected even with the correct secret. Worth it for fixed infrastructure, usually not worth it for ephemeral workers.
If a key leaks
- Revoke it. Immediately, before anything else — it is instant and reversible only by minting a new key.
- Mint a replacement with the same scopes and deploy.
- Read GET /v1/request_logs for calls you do not recognise.
- Check what the key's scopes allowed, and review that data specifically.
- If it could write, check for resources created or deleted while it was exposed.
A key pasted into a chat, a ticket, a screenshot or a public repository should be treated as compromised even if nothing looks wrong. Rotation is a two-minute job with a 24-hour overlap; an incident is not.
Reporting a vulnerability
Please report privately rather than opening a public issue, with enough detail to reproduce. See Support.
What's next
- Authentication — key format, rotation, 401 causes.
- Scopes — choosing the smallest set.
- Going live — the production checklist.