The Instant Compliance API authenticates every request with a bearer
API key.
Authorization: Bearer ic_live_<32+ characters>
The key prefix (ic_live_) is fixed so secret scanners (GitHub
Secret Scanning, GitGuardian, etc.) can recognise leaked keys
automatically.
How keys are stored
We never store the plaintext key. At creation we keep only:
- The first 12 characters (the prefix, for the UI label).
- The last 4 characters (so admins can identify which key is which).
- A SHA-256 hash of the full plaintext.
When a request arrives we hash the incoming bearer token and look it up
by hash, with a constant-time comparison. The plaintext is shown exactly
once at creation and never retrievable.
If you lose the plaintext key after closing the creation dialog, it is
gone — there is no “show key” button. Revoke the key and issue a new
one.
Issuing a key
Open Settings → Developers in Instant Compliance and click Create
key. You must hold the org.api-keys permission (Administrators have
it by default).
You will be asked for:
- Label — a name only used in the admin dashboard. Pick something
you will recognise six months later (e.g.
Zapier — HubSpot production).
- Scopes — see below.
- Expiry (optional) — useful for short-lived integrations or
one-off scripts.
Scopes
Scopes are the public, integrator-facing surface granted to a key. Each
scope maps to a backing internal permission, so a key can never exceed
what the role model allows for human users.
| Scope | Grants |
|---|
customers:write | POST /v1/customers, PATCH /v1/customers/{id} |
customers:read | GET /v1/customers, GET /v1/customers/{id} |
aml:read | GET /v1/customers/{id}/aml |
Grant the minimum scopes the integration needs. A reporting-only
integration that syncs status into your CRM should ask for
customers:read and aml:read only; it physically cannot write or
trigger billing.
Rotation
Best practice: rotate keys every 6–12 months, and immediately on:
- Departure of an engineer who had access to the plaintext.
- Any suspected leak (committed to git, posted in a support ticket,
etc.).
- Decommissioning the integration.
Rotation is “create new key → cut over the integration → revoke old
key”. The revoke is immediate — the next request authenticated with
the revoked key returns 401 unauthorized.
IP allowlist (optional)
Keys may be locked to a list of source IPs. When set, a request from
any other source is rejected at the auth layer before the scope check
runs — so a stolen key from an off-allowlist source cannot even probe
scopes. Useful for integrations that always call from a fixed VPC
egress.
What to do if a key leaks
- Revoke immediately in Settings → Developers. Effect is
instantaneous.
- Issue a fresh key for the integration.
- Audit the leak source and remove the secret from where it was
exposed (
git filter-repo, ticket scrub, etc.).
- Review the request log for that key to assess what was accessed.
Common errors
| HTTP | error.code | Cause |
|---|
| 401 | unauthorized | Header missing / malformed / wrong format / key revoked or expired |
| 403 | forbidden_scope | Key authenticated but lacks the scope this route requires |
See Errors for the full envelope shape.