Authentication & Scopes
Last verified: 2026-06-20 (Task #389 — Visa Intelligence API docs).
Every Visa Intelligence endpoint requires a per-customer API key. The key identifies your tenant (customer) and carries a fixed set of scopes that decide which endpoints it may call.
Sending the key
Use either header on every request:
| Header | Example |
|---|---|
X-Visa-Intel-Key: <key> | X-Visa-Intel-Key: vsk_live_abc123... |
Authorization: Bearer <key> | Authorization: Bearer vsk_live_abc123... |
If both are present, X-Visa-Intel-Key is checked first. If neither is
present you get visa_api_key_invalid (HTTP 401) — or
visa_api_key_unconfigured (HTTP 503) on a deployment that has no key
configured at all.
Key format
vsk_live_<random suffix>
- The
vsk_live_prefix is fixed (vsk= "visa server key"). - Only a hash of the full key is persisted, plus a short
key_prefixfor display. The plaintext is shown exactly once at issuance — if you lose it, rotate to a new key.
Scopes
Each endpoint requires exactly one scope. A key with the wrong scope
gets visa_api_key_insufficient_scope (HTTP 403) with a requiredScope
field naming what was missing.
| Scope | Grants access to |
|---|---|
visa:check | POST /v1/visa/check, GET /v1/visa/rules |
visa:changes | GET /v1/visa/changes and all GET/POST/DELETE /v1/visa/webhooks routes |
visa:sources | GET /v1/visa/sources/{countryCode}, GET /v1/visa/documents/{countryCode}, document download |
visa:health | GET /v1/visa/health |
The country snapshots endpoint (
GET /v1/visa/sources/{countryCode}/snapshots) is the one exception: it is gated by an admin session cookie, not by an API key, because snapshots can contain raw authoritative-source fragments. An API key will not authenticate there.
Customer keys vs. the master key
There are two kinds of credential:
- Customer key (
vsk_live_…) — issued per tenant, scope-checked, rate-limited, and audit-logged. This is what you use in production. - Master key — an environment-variable key (
VISA_INTEL_API_KEY) used only in development/testing. It implicitly satisfies every scope and bypasses per-key rate limits, but it is not allowed to manage webhooks:POST/GET/DELETE /v1/visa/webhooksreject a master key withvisa_webhook_master_key_forbidden(HTTP 403). Webhook management is customer-scoped by design so an endpoint always belongs to a real tenant.
Rotation
Rotating from the dashboard issues a fresh key with the same scopes and rate limit and revokes the old one. Because only the hash is stored, there is no "reveal" path for an existing key — rotate and redeploy.
Errors at a glance
| Code | HTTP | Cause |
|---|---|---|
visa_api_key_unconfigured | 503 | No key presented and none configured on this deployment. |
visa_api_key_invalid | 401 | No key, or the presented key doesn't resolve. |
visa_api_key_revoked | 401 | Key was revoked. |
visa_api_key_expired | 401 | Key's expires_at has passed. |
visa_api_customer_inactive | 403 | The tenant behind the key is disabled. |
visa_api_key_insufficient_scope | 403 | Key valid but missing the endpoint's scope (requiredScope). |
See errors.md for the full table and example envelopes.