Getting started

Authentication

Every API request carries a single Authorization: Bearer header. Server-to-server integrations use an API key; the dashboard uses short-lived session tokens issued by /v1/auth/login. This page covers the API-key path.

Account signup

POST/v1/signup

Public, limited to 5 attempts per IP per hour. Creates a tenant and its first admin user.

{
  "organizationName": "Acme Corp",        // required
  "email": "ops@acme.example",            // required
  "name": "Acme Ops",
  "password": "a-strong-passphrase",      // required, min 12 chars
  "accountType": "BUSINESS"               // or "INDIVIDUAL"; default BUSINESS
}
// 201 →
{"tenantId": "…", "userId": "…", "status": "PENDING_EMAIL_VERIFICATION", "message": "…"}

Then confirm the address with the emailed token, or trigger a resend:

POST /v1/signup/verify-email          {"token": "…"}   // → {"status":"EMAIL_VERIFIED", …}
POST /v1/signup/resend-verification  {"email": "…"}   // → always 202

New tenants start in PENDING_VERIFICATION: you can explore the API, create vaults, and register wallets, but value-moving endpoints stay blocked until identity verification (KYC/KYB) completes. Check progress with GET/v1/onboarding/status.

API keys

An API key is a keyId + secret pair sent as one bearer token, joined by a colon:

Authorization: Bearer qc_5f2a…e1:9c41…7d
#                     └─ keyId ─┘ └ secret ┘
PartFormat
keyIdqc_ + 32 hex characters
secret64 hex characters — shown once at issuance; only a hash is stored

Your first key is issued during onboarding in the dashboard (Keys page). The API surface manages existing keys only:

GET/v1/credentials

{"data": [
  {"keyId": "qc_…", "tenantId": "…", "label": "prod-backend", "status": "ACTIVE",
   "createdAt": "…", "expiresAt": null, "lastUsedAt": "…"}
]}
// secret material is never returned

POST/v1/credentials/rotate

{"keyId": "qc_…", "gracePeriodMinutes": 60}   // grace default: 24 h
// 200 →
{"newKeyId": "qc_…", "secret": "…",           // plaintext, shown once — store it now
 "oldKeyId": "qc_…", "oldKeyExpiresAt": "…"}

The old key keeps working until the grace period ends, then returns 401 credential rotated and grace period expired. Rotate regularly and on any suspicion of exposure.

Scopes

Keys can be scoped to read, write, or admin. A key with no scopes has full access. Prefer the narrowest scope that works — reporting jobs need only read.

Access protections

Request correlation Send an X-Request-ID header to correlate your logs with Qustody's — the same ID is echoed back as requestId in every error body.