Authentication
Authenticate in three tiers: account login (Bearer session), customer API credentials (owner x-api-key), then per-user tokens (Bearer, 24 hours with a 30-day refresh token).
The API authenticates in three tiers. Log in to get a session token, issue customer API credentials with it, then issue a token per user. Each tier unlocks the next.
Send every request over HTTPS—plain HTTP fails. Treat every token and key like a password: keep them server-side, store them in a secrets manager or environment variables, and never ship them in browser or mobile code. Rotate on a schedule and revoke anything you suspect is exposed.
Every response, including login and refresh, uses the standard envelope.
Two Bearer tokens, two audiences
Authorization: Bearer carries two different tokens depending on the API: the account session token (tier 1) authenticates SX Customers, and the user token (tier 3) authenticates SX Users. The owner x-api-key (tier 2) authenticates SX Connect.
1. Account login (Bearer session token)
Log in with your Sovera account email and password. Login returns a session object. Send its token as Authorization: Bearer <token> to manage your SX Customers resources—customers, credentials, the email poller, and webhooks.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | Sovera account email. | |
| password | string | Yes | Sovera account password. |
The session object
| Field | Type | Description |
|---|---|---|
| object | string | Always session. |
| token_type | string | Always BEARER. |
| token | string | Session token for Authorization: Bearer. |
| expires_at | string | null | Session token expiry, UTC. |
| refresh_token | string | null | Token for Refreshing the session. |
| refresh_token_expires_at | string | null | Refresh token expiry, UTC; null when the identity service doesn't report it. |
{
"email": "[email protected]",
"password": "your-password"
}Success Response (200 OK):
{
"success": true,
"data": {
"object": "session",
"token_type": "BEARER",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2NWYxYzJhOSIsImV4cCI6MTc5MTgyMDIwMH0.Qm9ndXNTaWduYXR1cmVGb3JFeGFtcGxlT25seQ",
"expires_at": "2026-10-12T15:30:00Z",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2NWYxYzJhOSIsInR5cCI6InJlZnJlc2giLCJleHAiOjE3OTI0MjE0MDB9.UmVmcmVzaFNpZ25hdHVyZUV4YW1wbGU",
"refresh_token_expires_at": "2026-10-19T14:30:00Z"
},
"meta": {
"timestamp": "2026-10-12T14:30:00Z",
"version": "v1",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}Error Response (401 Unauthorized):
{
"success": false,
"errors": [
{ "code": "INVALID_CREDENTIALS", "message": "Email or password is incorrect" }
],
"meta": {
"timestamp": "2026-10-12T14:30:00Z",
"version": "v1",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}curl -X POST "https://api.sandbox.sovera.io/sovx/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "your-password"
}'Errors: 401 INVALID_CREDENTIALS wrong email or password (one code whatever the cause; the response carries a www-authenticate header) · 422 VALIDATION_ERROR missing or invalid field · 429 RATE_LIMIT_EXCEEDED too many attempts (no retry-after; back off exponentially) · 502 BAD_GATEWAY the identity service is unavailable.
Send the token on every SX Customers request:
Authorization: Bearer YOUR_SESSION_TOKENOne session at a time
Each login or refresh invalidates the session token issued before it. Logging in twice, or refreshing while another request is in flight, retires the token you're still holding, and the next call fails with 401 UNAUTHORIZED. Keep one session per account and store the newest token and refresh_token every time.
Refreshing the session
Trade the refresh_token for a new session before expires_at instead of logging in again—that keeps you on a single session. The refresh token rotates: always store the refresh_token this call returns and use it for the next refresh.
| Field | Type | Required | Description |
|---|---|---|---|
| refresh_token | string | Yes | The latest refresh_token from login or a previous refresh. |
{
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2NWYxYzJhOSIsInR5cCI6InJlZnJlc2giLCJleHAiOjE3OTI0MjE0MDB9.UmVmcmVzaFNpZ25hdHVyZUV4YW1wbGU"
}Success Response (200 OK)—data is a new session object, as in login.
curl -X POST "https://api.sandbox.sovera.io/sovx/v1/auth/refresh/token" \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2NWYxYzJhOSIsInR5cCI6InJlZnJlc2giLCJleHAiOjE3OTI0MjE0MDB9.UmVmcmVzaFNpZ25hdHVyZUV4YW1wbGU"
}'Errors: 401 INVALID_REFRESH_TOKEN invalid, expired, or revoked refresh token (source.pointer /refresh_token; the response carries a www-authenticate header) · 422 VALIDATION_ERROR missing refresh_token · 429 RATE_LIMIT_EXCEEDED · 502 BAD_GATEWAY.
2. Customer API credentials (owner x-api-key)
With your Bearer session token, issue API credentials for a customer. The response is a credential object whose customer_secret is your owner x-api-key for the SX Connect APIs: create and manage users, issue user tokens, and read currencies, account data, and events. The secret appears only in this response; later reads show just customer_secret_prefix. See Customer management for listing and revoking credentials.
curl -X POST "https://api.sandbox.sovera.io/sovx/v1/customers/CUSTOMER_ID/credentials" \
-H "Authorization: Bearer YOUR_SESSION_TOKEN"Success Response (201 Created):
{
"success": true,
"data": {
"id": "8c2e4f6a-1b3d-4e5f-9a7c-0d2e4f6a8b1c",
"object": "credential",
"customer_id": "corp-redundant-firewall",
"customer_secret": "uiFkvaYbt1YfBO2NiXyi1txbdysIxa8H",
"customer_secret_prefix": "uiFkvaYb",
"is_owner": true,
"is_active": true,
"user_email": "[email protected]",
"user_name": "Acme Corp",
"expires_at": null,
"last_used_at": null,
"created_at": "2026-10-12T14:31:00Z",
"updated_at": "2026-10-12T14:31:00Z",
"created_by": "65f1c2a9",
"updated_by": "65f1c2a9"
},
"meta": {
"timestamp": "2026-10-12T14:31:00Z",
"version": "v1",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}Send the secret as your owner key on SX Connect requests:
x-api-key: YOUR_OWNER_API_KEY3. User token (Bearer)
To act for one user, issue a user token with your owner x-api-key, then send it as Authorization: Bearer. A user token reaches only its own user's data on the SX Users APIs—wallets, addresses, transfers, withdrawals, trading, balances, and transactions.
Each issuance returns a 24-hour access token (utk_…) and a 30-day, single-use refresh token (rt_…). Renew the pair with the refresh token—no owner key needed—before the access token expires. The user must be VERIFIED first. See User Tokens for issuing, refreshing, and bulk issuance.
curl -X POST "https://api.sandbox.sovera.io/sovx/v1/users/USER_ID/tokens" \
-H "x-api-key: YOUR_OWNER_API_KEY"Success Response (201 Created):
{
"success": true,
"data": {
"id": "bf1f8aa6-8b55-5650-8ee7-c7a9d29d0b5e",
"object": "user_token",
"user_id": "f4057807-52cf-4083-9ecb-283ef354fb2b",
"token": "utk_test_7Qm4Lr8Tz1V2x9Kf3Bn6Wd1Yb6Jk2Hc5Np8Rf2Lm6Tq",
"token_last4": "9Vx3",
"expires_at": "2026-10-13T14:30:00Z",
"created_at": "2026-10-12T14:30:00Z",
"created_by": "65f1c2a9e4b0a1d2c3f4a5b6",
"refresh_token": "rt_9f2c4e7a1b3d5f80c6e2a4b8d1f3e5a79f2c4e7a1b3d5f80c6e2a4b8d1f3e5a7",
"refresh_expires_at": "2026-11-11T14:30:00Z"
},
"meta": {
"timestamp": "2026-10-12T14:30:00Z",
"version": "v1",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}Send the token as the user's Bearer credential on SX Users requests:
Authorization: Bearer YOUR_USER_TOKENSecurity best practices
- Keep tokens and keys server-side—never in client-side code.
- Store credentials in environment variables or a secrets manager.
- Store the newest refresh token after every refresh; old ones stop working.
- Rotate keys on a schedule, and revoke anything that leaks.
- Call the API over HTTPS only.
- Watch the
x-rate-limit-*headers and back off on429(see Rate limits).
Common errors
Authentication failures return the standard error envelope with a 401 or 403 status.
401 Unauthorized
The request lacks valid credentials. The code is UNAUTHORIZED, or INVALID_CREDENTIALS / INVALID_REFRESH_TOKEN on the login and refresh endpoints. On x-api-key and user-token routes, source.header names the header that failed:
{
"success": false,
"errors": [
{
"code": "UNAUTHORIZED",
"message": "Token has expired; renew it with the refresh token",
"source": { "header": "authorization" }
}
],
"meta": {
"timestamp": "2026-10-13T14:30:05Z",
"version": "v1",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}Common causes:
- Missing or invalid
x-api-key, or a revoked credential. - A missing or expired
Authorization: Bearertoken—an account session or a user token older than 24 hours. Refresh it.
403 Forbidden
The credentials are valid but lack permission for this resource—for example, a user token on an owner-only SX Connect endpoint. The code is FORBIDDEN. Use the credential that matches the tier.
Getting Started
Make your first calls to the Crypto as a Service API in minutes: connectivity, login, credentials, users, tokens, wallets, and deposit addresses.
API conventions
The rules every Crypto as a Service endpoint follows: envelope, errors, idempotency, rate limits, pagination, filters, money, statuses, timestamps, networks, and pairs.