Customer Management
Create, read, update, and delete your customer account, and issue or revoke the API credentials it authenticates with.
Manage your customer account: create it, read and update its profile, delete it, and issue or revoke the API credentials your backend uses to call the rest of the platform. The customer is the tenant your end users live under—create it first, then issue a credential before you create users or open wallets.
Authentication: every endpoint on this page takes your dashboard session token as a Bearer token. The session must own the {customer_id} in the path; any other id answers 404 CUSTOMER_NOT_FOUND, so ids can't be probed across accounts. Deleting the customer and issuing or revoking credentials also require the account holder's session: a team member who shares the account gets 403 ACCOUNT_OWNER_REQUIRED, and nothing changes.
Authorization: Bearer YOUR_SESSION_TOKENResponses use the standard envelope and error format. POST and PATCH accept an optional x-idempotency-key header, except where noted.
The customer resource
id and customer_id carry the same platform customer id. status is always VERIFIED: a customer reaches this API only once it's verified. Unknown profile values come back as null, never as placeholders, and every business key is always present. Dates are UTC without milliseconds; see Timestamps.
Create Customer
Register your customer account. Pass the customer_id issued at registration, a contact email, and the legal entity name. The service checks the session owns that id, pulls the business profile, and stores the record. The response is the customer resource with a location header pointing at it.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| customer_id | string | Yes | Platform customer id issued at registration (max 48). |
| string | Yes | Primary contact email (max 255). | |
| entity_name | string | Yes | Legal name of the business entity (max 255). |
{
"customer_id": "corp-redundant-firewall",
"email": "[email protected]",
"entity_name": "Hedge Fund e-commerce"
}Success Response (201 Created):
{
"success": true,
"data": {
"id": "corp-redundant-firewall",
"object": "customer",
"customer_id": "corp-redundant-firewall",
"account_type": "CORPORATION",
"account_role": "CLIENT",
"account_purpose": null,
"first_name": "Hedge",
"last_name": "Fund e-commerce",
"email": "[email protected]",
"phone_country_code": "US",
"phone_number": null,
"business": {
"entity_name": "Hedge Fund e-commerce",
"incorporation_country": "VC",
"incorporation_state": "Kingstown",
"incorporation_date": "2012-11-15",
"organization_type": "LLC",
"business_type": "Fund Administrator",
"registration_number": "3201LLC2023",
"description": "crypto fund",
"is_accredited_investor": true,
"is_non_agent_intermediary": true,
"principal_place_country": "US",
"principal_place_state": "CA",
"principal_place_address": "1234 Flower Street",
"principal_place_city": "Los Angeles",
"principal_place_postal_code": "90403"
},
"status": "VERIFIED",
"created_at": "2026-10-12T14:03:21Z",
"updated_at": "2026-10-12T14:03:21Z",
"created_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd",
"updated_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd"
},
"meta": {
"timestamp": "2026-10-12T14:03:21Z",
"version": "v1",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}curl -X POST "https://api.sandbox.sovera.io/sovx/v1/customers" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_SESSION_TOKEN" \
-H "x-idempotency-key: 9a7c3e1f-5b2d-4c8e-a6f0-1d3b5e7f9a2c" \
-d '{
"customer_id": "corp-redundant-firewall",
"email": "[email protected]",
"entity_name": "Hedge Fund e-commerce"
}'Customer Fields
| Field | Type | Description |
|---|---|---|
| id | string | Platform customer id (same value as customer_id). |
| object | string | Always customer. |
| customer_id | string | Platform customer id. |
| account_type | string | INDIVIDUAL or CORPORATION. Read-only. |
| account_role | string | CLIENT or PARTNER. Read-only. |
| account_purpose | string | null | Primary use of the account. |
| first_name / last_name | string | null | Account holder name. |
| string | Primary contact email. Read-only after creation. | |
| phone_country_code | string | null | ISO 3166-1 alpha-2 country of the phone number. |
| phone_number | string | null | Contact phone number. |
| business | object | Business profile. Every key is present; unknown values are null. Booleans are is_accredited_investor and is_non_agent_intermediary. |
| status | string | Always VERIFIED. |
| created_at / updated_at | string | UTC timestamps. |
| created_by / updated_by | string | null | Actor that created or last changed the record. |
Errors: 401 UNAUTHORIZED missing or invalid session · 404 CUSTOMER_NOT_FOUND the session doesn't own this customer_id · 409 CUSTOMER_ALREADY_EXISTS (source.pointer: /customer_id) · 422 VALIDATION_ERROR invalid field, one error per field with source.pointer.
Get Customer
Return your customer resource. A deleted customer answers 404 CUSTOMER_NOT_FOUND.
GET https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewallSuccess Response (200 OK):
{
"success": true,
"data": {
"id": "corp-redundant-firewall",
"object": "customer",
"customer_id": "corp-redundant-firewall",
"account_type": "CORPORATION",
"account_role": "CLIENT",
"account_purpose": "Arbitrage Trading",
"first_name": "Hedge",
"last_name": "Fund e-commerce",
"email": "[email protected]",
"phone_country_code": "US",
"phone_number": "408-721-7741",
"business": {
"entity_name": "Hedge Fund e-commerce",
"incorporation_country": "VC",
"incorporation_state": "Kingstown",
"incorporation_date": "2012-11-15",
"organization_type": "LLC",
"business_type": "Fund Administrator",
"registration_number": "3201LLC2023",
"description": "crypto fund",
"is_accredited_investor": true,
"is_non_agent_intermediary": true,
"principal_place_country": "US",
"principal_place_state": "CA",
"principal_place_address": "1234 Flower Street",
"principal_place_city": "Los Angeles",
"principal_place_postal_code": "90403"
},
"status": "VERIFIED",
"created_at": "2026-10-12T14:03:21Z",
"updated_at": "2026-10-12T15:10:04Z",
"created_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd",
"updated_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd"
},
"meta": {
"timestamp": "2026-10-12T15:10:09Z",
"version": "v1",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}curl -X GET "https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewall" \
-H "Authorization: Bearer YOUR_SESSION_TOKEN"Errors: 401 UNAUTHORIZED missing or invalid session · 404 CUSTOMER_NOT_FOUND not owned by the session, or deleted.
Update Customer
Change profile fields. Send only what changes: a field you send replaces the stored value, null clears it, and a field you leave out stays as it is. business merges key by key the same way, so updating one business field never wipes the others. The response is the full customer resource.
account_type, account_role, email, and status aren't writable. Sending any of them, or any unknown field, answers 422 VALIDATION_ERROR with a source.pointer for each one. PUT /v1/customers/{customer_id} still works as a deprecated alias with the same merge behavior.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| account_purpose | string | null | No | Primary use of the account (max 200). |
| first_name | string | null | No | Account holder first name (max 100). |
| last_name | string | null | No | Account holder last name (max 100). |
| phone_country_code | string | null | No | ISO 3166-1 alpha-2 code, e.g. US. |
| phone_number | string | null | No | Contact phone number (max 20). |
| business | object | No | Business fields to merge (below). |
business object
Every field is optional and nullable.
| Field | Type | Description |
|---|---|---|
| entity_name | string | Legal name (max 255). |
| incorporation_country | string | ISO 3166-1 alpha-2. |
| incorporation_state | string | State or province of incorporation. |
| incorporation_date | string | YYYY-MM-DD. |
| organization_type | string | Legal structure, e.g. LLC. |
| business_type | string | Industry or activity. |
| registration_number | string | Registration or license number. |
| description | string | Short description of the business. |
| is_accredited_investor | boolean | Accredited investor flag. accredited_investor is a deprecated alias. |
| is_non_agent_intermediary | boolean | Non-agent intermediary flag. non_agent_intermediary is a deprecated alias. |
| principal_place_country | string | ISO 3166-1 alpha-2. |
| principal_place_state | string | State or province. |
| principal_place_address | string | Street address. |
| principal_place_city | string | City. |
| principal_place_postal_code | string | Postal code. |
{
"account_purpose": "Arbitrage Trading",
"phone_number": "408-721-7741",
"business": {
"incorporation_country": "US",
"organization_type": "LLC"
}
}Success Response (200 OK):
{
"success": true,
"data": {
"id": "corp-redundant-firewall",
"object": "customer",
"customer_id": "corp-redundant-firewall",
"account_type": "CORPORATION",
"account_role": "CLIENT",
"account_purpose": "Arbitrage Trading",
"first_name": "Hedge",
"last_name": "Fund e-commerce",
"email": "[email protected]",
"phone_country_code": "US",
"phone_number": "408-721-7741",
"business": {
"entity_name": "Hedge Fund e-commerce",
"incorporation_country": "US",
"incorporation_state": "Kingstown",
"incorporation_date": "2012-11-15",
"organization_type": "LLC",
"business_type": "Fund Administrator",
"registration_number": "3201LLC2023",
"description": "crypto fund",
"is_accredited_investor": true,
"is_non_agent_intermediary": true,
"principal_place_country": "US",
"principal_place_state": "CA",
"principal_place_address": "1234 Flower Street",
"principal_place_city": "Los Angeles",
"principal_place_postal_code": "90403"
},
"status": "VERIFIED",
"created_at": "2026-10-12T14:03:21Z",
"updated_at": "2026-10-12T15:10:04Z",
"created_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd",
"updated_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd"
},
"meta": {
"timestamp": "2026-10-12T15:10:04Z",
"version": "v1",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}curl -X PATCH "https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewall" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_SESSION_TOKEN" \
-d '{
"account_purpose": "Arbitrage Trading",
"phone_number": "408-721-7741",
"business": { "incorporation_country": "US", "organization_type": "LLC" }
}'Errors: 401 UNAUTHORIZED missing or invalid session · 404 CUSTOMER_NOT_FOUND not owned by the session, or deleted · 422 VALIDATION_ERROR invalid, read-only, or unknown field.
Delete Customer
Soft-delete your customer account. Every credential is revoked and the email poller is disabled in the same call. All user tokens issued under your credentials are revoked as well. Afterwards the customer and its sub-resources (credentials, email poller, webhook, vault reads) answer 404 CUSTOMER_NOT_FOUND. Account holder only.
DELETE https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewallSuccess Response (204 No Content)—empty body.
curl -X DELETE "https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewall" \
-H "Authorization: Bearer YOUR_SESSION_TOKEN"Errors: 401 UNAUTHORIZED missing or invalid session · 403 ACCOUNT_OWNER_REQUIRED the session belongs to a team member, not the account holder · 404 CUSTOMER_NOT_FOUND not owned by the session, or already deleted.
Generate Credentials
Issue an API credential for your backend. The response is the credential resource with customer_secret—the key you send as x-api-key. It's shown only on this response: store it right away. Send no body. Account holder only.
This endpoint ignores x-idempotency-key and never replays a response, so the secret is never cached. Every successful call issues a new credential.
POST https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewall/credentialsSuccess Response (201 Created):
{
"success": true,
"data": {
"id": "a3f1c2d4-5e6f-4081-92a3-b4c5d6e7f809",
"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": "Hedge Fund e-commerce",
"expires_at": null,
"last_used_at": null,
"created_at": "2026-10-12T14:05:00Z",
"updated_at": "2026-10-12T14:05:00Z",
"created_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd",
"updated_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd"
},
"meta": {
"timestamp": "2026-10-12T14:05:00Z",
"version": "v1",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}curl -X POST "https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewall/credentials" \
-H "Authorization: Bearer YOUR_SESSION_TOKEN"Credential Fields
| Field | Type | Description |
|---|---|---|
| id | string | Credential id (UUID). |
| credential_id | string | Same value as id. Returned by the list only. |
| object | string | Always credential. |
| customer_id | string | Owning customer. |
| customer_secret | string | The API key. Only on the create response. |
| customer_secret_prefix | string | null | First 8 characters of the key, to tell credentials apart. |
| is_owner | boolean | Whether this is an owner credential. |
| is_active | boolean | Whether the credential authenticates requests. |
| user_email / user_name | string | null | Contact the credential was issued for. |
| expires_at | string | null | Always null: credentials don't expire today. |
| last_used_at | string | null | Last time the credential authenticated a request, UTC; null until its first use. Updated at most once a minute. |
| created_at / updated_at | string | UTC timestamps. |
| created_by / updated_by | string | null | Actor that created or last changed the credential. |
Errors: 401 UNAUTHORIZED missing or invalid session · 403 ACCOUNT_OWNER_REQUIRED the session belongs to a team member, not the account holder · 404 CUSTOMER_NOT_FOUND not owned by the session, or deleted · 502 CREDENTIAL_ISSUANCE_FAILED the key couldn't be issued; try again later.
List Credentials
List your active credentials, newest first, with cursor pagination. The secret is never returned here—only its prefix.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| filter[limit] | integer | No | Items per page (default 25, max 100). |
| cursor | string | No | Opaque cursor from meta.pagination.navigation. |
| filter[order] | string | No | created_at or updated_at, ASC or DESC (default created_at DESC). |
| filter[where][is_owner][eq] | string | No | true or false. |
| filter[where][created_at][gte|lte|between] | string | No | UTC date-time ending in Z. |
GET https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewall/credentials?filter[limit]=25Success Response (200 OK):
{
"success": true,
"data": [
{
"id": "a3f1c2d4-5e6f-4081-92a3-b4c5d6e7f809",
"credential_id": "a3f1c2d4-5e6f-4081-92a3-b4c5d6e7f809",
"object": "credential",
"customer_id": "corp-redundant-firewall",
"customer_secret_prefix": "uiFkvaYb",
"is_owner": true,
"is_active": true,
"user_email": "[email protected]",
"user_name": "Hedge Fund e-commerce",
"expires_at": null,
"last_used_at": "2026-10-12T15:42:00Z",
"created_at": "2026-10-12T14:05:00Z",
"updated_at": "2026-10-12T14:05:00Z",
"created_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd",
"updated_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd"
}
],
"meta": {
"timestamp": "2026-10-12T15:00:41Z",
"version": "v1",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"pagination": {
"records": { "limit": 25, "has_next": false, "has_previous": false },
"navigation": { "next": null, "previous": null }
}
}
}curl -X GET "https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewall/credentials?filter[limit]=25" \
-H "Authorization: Bearer YOUR_SESSION_TOKEN"Errors: 401 UNAUTHORIZED missing or invalid session · 404 CUSTOMER_NOT_FOUND not owned by the session, or deleted · 422 VALIDATION_ERROR invalid filter, limit, or cursor (source.parameter names it).
Revoke Credential
Revoke one credential. The key is rejected from the next request on, and it drops out of the list. Every user token and refresh token issued with this key is revoked too: re-issue them with the new key (POST /v1/users/tokens) before revoking the old one. Your dashboard session isn't affected. The id returned by older lists is still accepted. Account holder only.
DELETE https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewall/credentials/a3f1c2d4-5e6f-4081-92a3-b4c5d6e7f809Success Response (204 No Content)—empty body.
curl -X DELETE "https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewall/credentials/a3f1c2d4-5e6f-4081-92a3-b4c5d6e7f809" \
-H "Authorization: Bearer YOUR_SESSION_TOKEN"Errors: 401 UNAUTHORIZED missing or invalid session · 403 ACCOUNT_OWNER_REQUIRED the session belongs to a team member, not the account holder · 404 CUSTOMER_NOT_FOUND not owned by the session, or deleted · 404 CREDENTIAL_NOT_FOUND no active credential with that id.