Authentication
Every /v1 endpoint requires an API key that belongs to a business (workspace). There are no
unauthenticated endpoints under /v1, and there are no OAuth flows or session cookies on this
surface.
Base URL: https://api.nuansis.co
Presenting the key
Section titled “Presenting the key”Send the key as a bearer token:
Authorization: Bearer nvs_live_sk_1a2b3c4d5e6f_9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a0X-API-Key is also accepted as an alternative header. If both are present and Authorization
carries a Bearer token, Authorization wins; otherwise X-API-Key is used.
X-API-Key: nvs_live_sk_1a2b3c4d5e6f_9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a0Keys are matched by their non-secret prefix and sha256(secret). The plaintext key is never stored,
which is why it is shown only once when it is created.
Key format
Section titled “Key format”nvs_<environment>_sk_<prefix>_<secret>| Part | Value |
|---|---|
environment |
live or test |
prefix |
12 lowercase hex characters, non-secret, used for identification |
secret |
64 lowercase hex characters, stored only as a SHA-256 hash |
A string that does not match this shape is rejected before any database lookup.
Scopes
Section titled “Scopes”A key is minted with a subset of four scopes. A route declares the scopes it needs; the key must hold all of them.
| Scope | Grants |
|---|---|
verification:write |
Start a verification and submit a code for checking |
collections:write |
Create one-off collections, reserved accounts, and deposits |
payouts:write |
Create transfers, save beneficiaries, and withdraw to a beneficiary |
read |
Read any resource |
Two rules make scopes forgiving in one direction only:
- Write implies read. A key holding any
*:writescope satisfies areadrequirement. - Read does not imply write. A key minted with only
readis rejected with403on every mutating endpoint.
If a key is minted without an explicit scope list, it is granted all four scopes. If a supplied list contains only unknown values, it also falls back to all four; unknown values mixed with valid ones are dropped.
Scope required by endpoint
Section titled “Scope required by endpoint”| Endpoint | Required scope |
|---|---|
GET /v1/capabilities |
none beyond a valid key |
POST /v1/cards |
none beyond a valid key (returns 501) |
POST /v1/verifications |
verification:write |
POST /v1/verifications/:reference/check |
verification:write |
GET /v1/verifications/:reference |
read |
POST /v1/collections |
collections:write |
GET /v1/collections/:id |
read |
POST /v1/reserved-accounts |
collections:write |
GET /v1/reserved-accounts |
read |
GET /v1/reserved-accounts/:id |
read |
POST /v1/deposits |
collections:write |
POST /v1/transfers |
payouts:write |
POST /v1/withdrawals |
payouts:write |
POST /v1/beneficiaries |
payouts:write |
GET /v1/beneficiaries |
read |
GET /v1/balances |
read |
GET /v1/channels |
read |
GET /v1/recipients |
read |
GET /v1/transactions |
read |
GET /v1/banks |
read |
POST /v1/banks/resolve |
read |
Rejected requests
Section titled “Rejected requests”Missing or invalid key — 401
Section titled “Missing or invalid key — 401”A missing key and a key that does not validate both return 401. The distinction is carried in the
message:
{ "error": { "code": "unauthorized", "message": "missing_api_key" }, "request_id": "8b1f5a2c-6a4d-4f0e-9f7a-2c3d4e5f6a7b"}{ "error": { "code": "unauthorized", "message": "invalid_api_key" }, "request_id": "8b1f5a2c-6a4d-4f0e-9f7a-2c3d4e5f6a7b"}invalid_api_key covers a malformed string, an unknown prefix/secret pair, and a revoked key. The
API deliberately does not say which.
Valid key, insufficient scope — 403
Section titled “Valid key, insufficient scope — 403”{ "error": { "code": "insufficient_scope", "message": "This API key is missing the required scope(s)", "details": { "required": ["payouts:write"], "granted": ["read"], "missing": ["payouts:write"] } }, "request_id": "8b1f5a2c-6a4d-4f0e-9f7a-2c3d4e5f6a7b"}Use details.missing to decide whether to retry with a different key or to fix the key’s
permissions.
Rotation and revocation
Section titled “Rotation and revocation”Keys are independent credentials, so rotation is a two-step deploy rather than an in-place edit:
- Create a new key with the same scopes under Settings → API keys.
- Deploy it to your environment and confirm traffic is succeeding.
- Revoke the old key with
DELETE /api-keys/:id(dashboard session auth) or the dashboard’s revoke action.
Revocation sets revoked_at. The authentication lookup filters on revokedAt IS NULL, so a
revoked key fails on the very next request — there is no grace period and no cached validation.
last_used_at is updated at most once per minute per key, so it is a useful signal that a key is
still in use, not a precise audit trail.
Request IDs
Section titled “Request IDs”Every response includes X-Request-Id. If you send an X-Request-Id header, the API uses your value
verbatim; otherwise it generates a UUID. Successful responses echo the same value as
meta.request_id; errors echo it as the top-level request_id.