Flows

User Onboarding Workflow

Complete guide to onboarding a new user: create an account, generate a token, create a wallet, and generate a deposit address.

Onboarding turns a brand-new person into an account that can hold crypto, trade, and withdraw. This guide walks the full sequence end to end, in the order the API expects it.

Overview

Each step builds on the one before it. You create the user with your owner key, mint a token so that user can act on its own behalf, give the user a wallet to hold funds, then generate an address so money can flow in.

  1. Create a user account
  2. Generate an authentication token
  3. Create a wallet
  4. Generate a deposit address

When you finish, you'll hold a user_id, a user token, a wallet_id, and a deposit address — everything later flows like trading and withdrawals depend on.

Estimated time: 5-10 minutes Prerequisites: your owner API key (x-api-key)

Authentication by step

Each step authenticates as the actor that performs it:

  • Create and manage users, generate tokens — your owner key, x-api-key: YOUR_OWNER_API_KEY (SX Connect).
  • Act on the user (wallets, addresses) — the user token from Step 2, sent as Authorization: Bearer YOUR_USER_TOKEN.

Step-by-Step Guide

Step 1: Create User Account

Start by registering the person. This creates the identity that owns every wallet, balance, and transaction that follows. Send the holder's KYC details under individual.

POSThttps://api.sandbox.sovera.io/sovx/v1/users
curl -X POST "https://api.sandbox.sovera.io/sovx/v1/users" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_OWNER_API_KEY" \
  -d '{
    "account_type": "individual",
    "account_role": "third",
    "account_purpose": "investing",
    "first_name": "John",
    "last_name": "Doe",
    "email": "[email protected]",
    "phone_country_code": "US",
    "phone_number": "2252542523",
    "individual": {
      "dob": "1990-10-15",
      "residential_country_code": "US",
      "residential_address": "123 Sovera Lane",
      "residential_city": "Cheyenne",
      "residential_state": "WY",
      "residential_postal_code": "82001",
      "id_type": "ssn",
      "id_number": "123456789",
      "id_country_code": "US"
    }
  }'

Response:

{
  "success": true,
  "data": {
    "account_type": "individual",
    "account_role": "third",
    "account_purpose": "investing",
    "user_id": "f4057807-52cf-4083-9ecb-283ef354fb2b",
    "first_name": "John",
    "last_name": "Doe",
    "email": "[email protected]",
    "phone_country_code": "US",
    "phone_number": "2252542523",
    "status": "PENDING",
    "created_at": "2026-01-15T10:30:00.000Z",
    "updated_at": "2026-01-15T10:30:00.000Z",
    "individual": {
      "dob": "1990-10-15",
      "residential_country_code": "US",
      "residential_address": "123 Sovera Lane",
      "residential_city": "Cheyenne",
      "residential_state": "WY",
      "residential_postal_code": "82001",
      "id_type": "ssn",
      "id_number": "123456789",
      "id_country_code": "US"
    }
  },
  "meta": {
    "timestamp": "2026-01-15T10:30:00.000Z",
    "version": "v1",
    "trace_id": "5b8f3a9d-2c7e-4a1b-9f6d-0e3c2b1a4d5f"
  }
}

Save the user_id. Every later step — token, wallet, address — is scoped to it. A new user starts in PENDING and moves to VERIFIED once KYC clears.

See Create User for full request details.

Step 2: Generate User Authentication Token

The user now exists, but it can't act on its own yet. Use your owner key to mint a token so calls can be made on the user's behalf. Calling this again for the same user issues a fresh token and invalidates the previous one.

POSThttps://api.sandbox.sovera.io/sovx/v1/users/:user_id/token
curl -X POST "https://api.sandbox.sovera.io/sovx/v1/users/f4057807-52cf-4083-9ecb-283ef354fb2b/token" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_OWNER_API_KEY"

Response:

{
  "success": true,
  "data": {
    "token": "012d23b0d9a7d6c7d0b0429963eece727c4eca18635978d0bd6ffe6d1eaaed10",
    "user_id": "f4057807-52cf-4083-9ecb-283ef354fb2b",
    "expires": "2027-01-15T10:30:00.000Z"
  },
  "meta": {
    "timestamp": "2026-01-15T10:30:00.000Z",
    "version": "v1",
    "trace_id": "5b8f3a9d-2c7e-4a1b-9f6d-0e3c2b1a4d5f"
  }
}

The user token is valid for one year (expires is an ISO 8601 timestamp). Save it and send it as Authorization: Bearer YOUR_USER_TOKEN for calls made on the user's behalf.

See Generate Token for full request details.

Step 3: Create Wallet

A wallet is where the user's crypto lives. Create one so the account has somewhere to receive deposits, settle trades, and fund withdrawals. Act as the user with the Bearer token from Step 2. Each network/currency pair provisions a deposit address, returned in addresses[].

POSThttps://api.sandbox.sovera.io/sovx/v1/users/:user_id/wallets
curl -X POST "https://api.sandbox.sovera.io/sovx/v1/users/f4057807-52cf-4083-9ecb-283ef354fb2b/wallets" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_USER_TOKEN" \
  -d '{
    "name": "Main Wallet",
    "description": "Main wallet for all transactions",
    "wallet_type": "virtual",
    "networks": [
      { "name": "networks/bitcoin-testnet", "currency": "btc" }
    ]
  }'

Response:

{
  "success": true,
  "data": {
    "vault_wallet_id": "wal_8f3a9d2c7e4a",
    "wallet_id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "name": "Main Wallet",
    "description": "Main wallet for all transactions",
    "networks": [
      { "name": "networks/bitcoin-testnet", "currency": "btc" }
    ],
    "is_active": true,
    "created_at": "2026-01-15T10:30:00.000Z",
    "wallet_type": "virtual",
    "addresses": [
      {
        "address_id": "ad1b2c3d-4e5f-4a6b-8c9d-0e1f2a3b4c5d",
        "currency": "btc",
        "network": "networks/bitcoin-testnet",
        "address": "tb1qexampleaddressxxxxxxxxxxxxxxxxxxxxxx"
      }
    ]
  },
  "meta": {
    "timestamp": "2026-01-15T10:30:00.000Z",
    "version": "v1",
    "trace_id": "5b8f3a9d-2c7e-4a1b-9f6d-0e3c2b1a4d5f"
  }
}

Save the wallet_id. Creating the wallet already provisions one address per network, but you can generate more for other currencies next.

See Create Wallet for full request details.

Step 4: Generate Deposit Address

Generate a deposit address so the user can fund the wallet — anyone can send the chosen currency to this address and it lands in the wallet. If the wallet already has an address for that currency and network, the existing one is returned. Act as the user with the Bearer token.

POSThttps://api.sandbox.sovera.io/sovx/v1/wallets/:wallet_id/address
curl -X POST "https://api.sandbox.sovera.io/sovx/v1/wallets/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d/address" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_USER_TOKEN" \
  -d '{
    "currency": "btc",
    "network": "bitcoin-testnet"
  }'

Response:

{
  "success": true,
  "data": {
    "wallet_id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "vault_wallet_id": "vault-7f3a2b1c",
    "user_id": "f4057807-52cf-4083-9ecb-283ef354fb2b",
    "name": "Main Wallet",
    "description": "Primary trading wallet",
    "addresses": [
      {
        "address_id": "b2c3d4e5-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
        "currency": "btc",
        "network": "bitcoin-testnet",
        "address": "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"
      }
    ],
    "created_at": "2026-01-15T10:00:00.000Z",
    "updated_at": "2026-01-15T10:30:00.000Z"
  },
  "meta": { "timestamp": "2026-01-15T10:30:00.000Z", "version": "v1", "trace_id": "5b8f3a9d-2c7e-4a1b-9f6d-0e3c2b1a4d5f" }
}

See Generate Address for full request details.

With an address in hand, onboarding is done: the user can receive funds and you can move on to trading or withdrawals.

Next Steps

After onboarding:

  1. Check Balance — Monitor the wallet balance
  2. Execute Trade — Start trading
  3. Process Withdrawal — Withdraw funds

Troubleshooting

User Already Exists

Error: 409 CONFLICT Solution: The email, phone_number, or user_id is already in use. Use unique values or retrieve the existing user.

Validation Failed

Error: 422 UNPROCESSABLE_ENTITY Solution: Check the field-level messages in errors[]. The phone_number must be a valid mobile number for the given phone_country_code, and the holder must be 18 or older.

Wallet Creation Failed

Error: 400 BAD_REQUEST Solution: The name must be unique per user, and the customer must have a vault configured.

Support

Need help? Email [email protected]

On this page