Skip to content

Quickstart ​

This sequence verifies the core Wallet API integration. First install Node.js, curl, openssl, and jq, then configure the issued integration values as environment variables.

bash
export WALLET_BASE_URL='https://{environment-api-host}'
export WALLET_API_KEY='{issued-api-key}'
export WALLET_HMAC_KEY='{issued-hmac-key}'

wallet_request ​

wallet_request is a shell function defined to call the Wallet API. Its call format is wallet_request <HTTP method> <path and query without the Base URL> [JSON body]. Run the entire code block below in the shell where you configured the environment variables. Configure those variables and register the function again when opening a new shell.

It creates a fresh timestamp and nonce for every request and signs the exact path and body sent over HTTP with HMAC-SHA256.

bash
wallet_request() {
  local method="$1"
  local request_path="$2"
  local body="${3-}"
  local timestamp nonce signature
  timestamp="$(node -e 'process.stdout.write(String(Date.now()))')"
  nonce="$(node -e 'process.stdout.write(require("crypto").randomUUID())')"
  signature="$(printf '%s\n\n%s\n\n%s\n\n%s\n\n%s' \
    "$method" "$request_path" "$timestamp" "$nonce" "$body" \
    | openssl dgst -sha256 -hmac "$WALLET_HMAC_KEY" -binary \
    | openssl base64 -A)"

  if [ -n "$body" ]; then
    curl -sS -X "$method" "$WALLET_BASE_URL$request_path" \
      -H "X-API-KEY: $WALLET_API_KEY" \
      -H "X-TIMESTAMP: $timestamp" \
      -H "X-NONCE: $nonce" \
      -H "X-SIGNATURE: $signature" \
      -H 'Content-Type: application/json' \
      --data-raw "$body"
  else
    curl -sS -X "$method" "$WALLET_BASE_URL$request_path" \
      -H "X-API-KEY: $WALLET_API_KEY" \
      -H "X-TIMESTAMP: $timestamp" \
      -H "X-NONCE: $nonce" \
      -H "X-SIGNATURE: $signature"
  fi
}

This helper is intended for running the quickstart. Production code should add timeouts, response validation, and a bounded retry policy. See HMAC request signing for the complete signing rules.

1. Discover reference data ​

This example uses the Ethereum Sepolia testnet. See Supported Networks for mainnet/testnet classification and the network catalog.

bash
usdt_response="$(wallet_request GET '/asset-types?code=USDT&page=1&page_size=20')"
sepolia_response="$(wallet_request GET '/networks?is_active=true&page=1&page_size=100')"
printf '%s\n' "$usdt_response" | jq
printf '%s\n' "$sepolia_response" | jq

export ASSET_TYPE_ID="$(printf '%s' "$usdt_response" | jq -er '.data.items[0].id // empty')"
export NETWORK_ID="$(printf '%s' "$sepolia_response" | jq -er '.data.items[] | select(.chain_id == 11155111) | .network_id')"

wallet_request GET "/assets/by-type-network?asset_type_id=$ASSET_TYPE_ID&network_id=$NETWORK_ID" | jq

Confirm success: true, the USDT asset, and the Ethereum Sepolia network. Identify Sepolia by chain_id: 11155111. If it is absent, check subsequent pages and availability in the target environment, then stop until resolved. The asset/network combination must also have data.is_active: true.

Stop before the next request if any response fails or an ID is empty. The example's curl -sS can print JSON even for HTTP errors; | jq only formats the response. Check both the HTTP status and success, and never use null as an ID.

2. Create or reuse a customer account ​

Look up /users/{uid}/accounts first because POST /accounts is not idempotent. Create a USER account only when the intended account does not exist, then persist its account_id.

bash
export CUSTOMER_UID='user-tutorial-001'
wallet_request GET "/users/$CUSTOMER_UID/accounts" | jq

If the intended active USER account exists, set its returned account_id and skip creation. When several accounts exist, select one using your persisted customer mapping.

bash
export ACCOUNT_ID='{existing-active-user-account-id}'

Run the following code only when the account is absent.

bash
account_body="$(jq -nc --arg uid "$CUSTOMER_UID" \
  '{uid:$uid,account_type:"USER",metadata:{source:"quickstart"}}')"
account_response="$(wallet_request POST '/accounts' "$account_body")"
printf '%s\n' "$account_response" | jq
export ACCOUNT_ID="$(printf '%s' "$account_response" | jq -er '.data.account_id // empty')"

Use GET /accounts/{account_id} to verify uid, account_type: USER, and status: ACTIVE, then store the customer mapping. If the create response is lost, query the account list for the same uid first.

3. Issue a deposit address ​

Call POST /accounts/{account_id}/deposit-addresses with numeric asset_type_id and network_id. Store the returned address, network, and tag_or_memo together.

bash
address_body="{\"asset_type_id\":$ASSET_TYPE_ID,\"network_id\":$NETWORK_ID}"
address_response="$(wallet_request POST "/accounts/$ACCOUNT_ID/deposit-addresses" "$address_body")"
printf '%s\n' "$address_response" | jq

4. Verify the wallet ​

bash
wallet_request GET "/accounts/$ACCOUNT_ID" | jq
wallet_request GET "/accounts/$ACCOUNT_ID/balances" | jq

Continue with the Wallet tutorial for deposits and withdrawals or the Digital Payment tutorial for customer-to-business payments.

Completion criteria ​

The quickstart is complete when:

  • repeated provisioning reuses the same intended account rather than creating duplicates;
  • the stored deposit destination includes network and memo information;
  • balance amounts remain strings or decimal-safe values;
  • all failed responses retain their upstream request_id; and
  • rerunning read steps is safe.

Do not send real assets during quickstart. Use the test network and verify the selected asset deployment is active before requesting faucet or test-token funds.

OOLIN is a digital asset operations infrastructure product by BPMG.