Customer deposit wallets
Customer wallets give a known customer a reusable deposit address. Relay associates confirmed deposits with your userId, calculates the configured fee, and queues the merchant amount for settlement to the saved organization destination.
Use this model for account funding and repeated deposits. Use a payment intent when each order needs its own amount and lifecycle.
Get or create a wallet#
POST /customer-wallets
The operation is get-or-create for the organization, case-sensitive userId, network, and pinned chain identity. Calling it again returns the existing address, enrolls the requested token if needed, refreshes its saved settlement destination, and renews a two-hour fast-detection window.
Request fields#
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | Your stable, organization-scoped customer ID. Case-sensitive; 1–128 characters. |
network | string | yes | tron or solana. |
token | string | yes | USDT or USDC, subject to active configuration. |
curl --request POST \
--url https://bridge.relayfinance.io/customer-wallets \
--header 'Content-Type: application/json' \
--header 'accesskey: YOUR_ORGANIZATION_API_KEY' \
--data '{
"userId": "customer_28491",
"network": "solana",
"token": "USDC"
}'{
"success": true,
"data": {
"id": "cwallet_example",
"assetId": "cwasset_example",
"userId": "customer_28491",
"network": "solana",
"chainIdentity": "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
"address": "HkYExampleOwnerAddress",
"token": "USDC",
"tokenContract": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"tokenAccount": "3pExampleAssociatedTokenAccount",
"watchUntil": "2026-09-20T14:00:00.000Z",
"retainedFees": "0.000000",
"nextFeeSweepAt": "2026-10-01T00:00:00.000Z"
},
"meta": {
"requestId": "7944aed7-cef2-4d8f-b942-3d8e4974f57f"
}
}Response fields#
| Field | Type | Description |
|---|---|---|
id | string | Wallet ID used by the read and history endpoints. |
assetId | string | Enrollment ID for this wallet/token pair. |
userId | string | Exact customer ID supplied by your system. |
network | string | Wallet network. |
chainIdentity | string | Pinned chain identity used for evidence validation. |
address | string | Owner/deposit address. |
token | string | Enrolled token. |
tokenContract | string | Pinned token contract or mint. |
tokenAccount | string or null | Solana associated token account; null on TRON. |
watchUntil | string | End of the renewed fast-detection window. |
retainedFees | decimal string | Confirmed, unreserved Relay fees waiting for the scheduled fee sweep. |
nextFeeSweepAt | string | Next scheduled fee collection date. |
Wallet creation requires an active asset, token contract, configured customer-wallet fee policy, and saved settlement destination for the organization. The saved destination cannot be the customer deposit address.
Get a wallet#
GET /customer-wallets/{id}
Returns the wallet and every token enrollment currently attached to it.
{
"success": true,
"data": {
"id": "cwallet_example",
"userId": "customer_28491",
"network": "solana",
"address": "HkYExampleOwnerAddress",
"assets": [
{
"assetId": "cwasset_example",
"token": "USDC",
"tokenAccount": "3pExampleAssociatedTokenAccount",
"retainedFees": "0.000000"
}
]
},
"meta": {
"requestId": "946b12aa-7b1f-48b0-8653-ed71936617f6"
}
}List deposits#
GET /customer-wallets/{id}/deposits?limit=20&offset=0
| Query field | Type | Default | Limits |
|---|---|---|---|
limit | integer | 20 | 1–100 |
offset | integer | 0 | 0–1,000,000 |
The endpoint returns an array in data and pagination details in meta.pagination.
{
"success": true,
"data": [
{
"id": "deposit_example",
"assetId": "cwasset_example",
"transactionHash": "5TfExampleSignature",
"blockTimestamp": "2026-09-20T11:51:04.000Z",
"amount": "100.000000",
"fee": "1.000000",
"merchantAmount": "99.000000",
"status": "confirmed",
"createdAt": "2026-09-20T11:51:10.000Z",
"updatedAt": "2026-09-20T11:51:10.000Z"
}
],
"meta": {
"requestId": "57738670-36ad-46ed-8fb2-624ca1d39183",
"pagination": {
"total": 1,
"limit": 20,
"offset": 0,
"hasMore": false
}
}
}Deposit status starts as confirmed when it is eligible for settlement, or review_required when Relay cannot safely apply a fee and payout. After the linked merchant transfer is verified, the deposit becomes settled; an uncertain transfer can also move it to review_required.
List transfers#
GET /customer-wallets/{id}/transfers?limit=20&offset=0
Transfer records describe outgoing merchant payouts and periodic Relay fee collections.
| Field | Type | Description |
|---|---|---|
kind | string | merchant or fee. |
depositId | string or null | Source deposit for a merchant transfer. |
destination | string | Destination captured when the transfer was queued. |
amount | decimal string | Exact outgoing amount. |
status | string | queued, submitted, settled, or review_required. |
transactionHash | string or null | On-chain hash after submission. |
lastError | string or null | Safe operational status for deferred or reviewed work. |
nextAttemptAt | string | Next scheduled processing or verification time. |
One outgoing operation runs at a time per wallet across all enrolled tokens. A review_required transfer blocks later outgoing work until Relay reconciles it; do not attempt to replace or resend the transfer yourself.
Webhook events#
Subscribe to the wallet_event action in the dashboard. Customer-wallet event types are:
customer_wallet.deposit_confirmedcustomer_wallet.deposit_review_requiredcustomer_wallet.merchant_settledcustomer_wallet.merchant_review_requiredcustomer_wallet.fee_settledcustomer_wallet.fee_review_requiredcustomer_wallet.transfer_review_required
deposit_confirmed means the incoming funds were credited and a payout was queued. Only merchant_settled proves the outgoing merchant payout was verified on-chain.
Common errors#
| HTTP | Message | Cause |
|---|---|---|
400 | Asset is unavailable | Inactive asset, missing contract, or unsupported configuration |
400 | Customer wallet fees are not configured for this asset | No applicable fee policy |
400 | saved settlement error | No approved settlement destination for the network/token |
400 | Wallet asset contract changed; reconciliation required | Existing wallet enrollment is pinned to another contract |
404 | Customer wallet not found | The ID is absent or belongs to another organization |