English
Reconcile Payment Transactions
Use the ledger as the finalized balance-movement record and the deposit or withdrawal detail as the business-status record.
| Event | Customer account | Merchant payment account |
|---|---|---|
| External USDT deposit | DEPOSIT / CREDIT | — |
| Customer payment | INTERNAL_OUT / DEBIT | INTERNAL_IN / CREDIT |
| External settlement | — | WITHDRAW / DEBIT |
The transaction type codes are DEPOSIT=1000, WITHDRAW=2000, INTERNAL_OUT=3000, INTERNAL_IN=4000, and ADJUSTMENT=5000.
Query both account ledgers
bash
wallet_request GET "/accounts/$USER_ACCOUNT_ID/ledger?asset_type_id=$ASSET_TYPE_ID&after_id=0&limit=100" | jq
wallet_request GET "/accounts/$PAYMENT_ACCOUNT_ID/ledger?asset_type_id=$ASSET_TYPE_ID&after_id=0&limit=100" | jqLink the customer INTERNAL_OUT and merchant INTERNAL_IN entries through their shared ref_id, then retrieve GET /withdrawals/{ref_id} when detailed payment status is required.
Retrieve a single ledger entry
Keep account_id and ledger_id together; a ledger ID belongs to one account.
bash
export USER_LEDGER_ID='{ledger-id-from-customer-list}'
export PAYMENT_LEDGER_ID='{ledger-id-from-merchant-list}'
wallet_request GET "/accounts/$USER_ACCOUNT_ID/ledger/$USER_LEDGER_ID" | jq
wallet_request GET "/accounts/$PAYMENT_ACCOUNT_ID/ledger/$PAYMENT_LEDGER_ID" | jqSynchronize incrementally
Maintain an independent cursor for each account and resource:
- customer external deposits
- customer-sent payments
- merchant-sent withdrawals
- customer ledger
- merchant ledger
Initialize to 0 only when starting the first full synchronization. On restart, restore each resource/account/filter cursor from your database rather than overwriting it with the following values.
bash
export USER_DEPOSIT_CURSOR='0'
export USER_WITHDRAWAL_CURSOR='0'
export PAYMENT_WITHDRAWAL_CURSOR='0'
export USER_LEDGER_CURSOR='0'
export PAYMENT_LEDGER_CURSOR='0'bash
wallet_request GET "/deposits?account_id=$USER_ACCOUNT_ID&type=EXTERNAL&after_id=$USER_DEPOSIT_CURSOR&limit=100" | jq
wallet_request GET "/withdrawals?account_id=$USER_ACCOUNT_ID&after_id=$USER_WITHDRAWAL_CURSOR&limit=100" | jq
wallet_request GET "/withdrawals?account_id=$PAYMENT_ACCOUNT_ID&after_id=$PAYMENT_WITHDRAWAL_CURSOR&limit=100" | jq
wallet_request GET "/accounts/$USER_ACCOUNT_ID/ledger?asset_type_id=$ASSET_TYPE_ID&after_id=$USER_LEDGER_CURSOR&limit=100" | jq
wallet_request GET "/accounts/$PAYMENT_ACCOUNT_ID/ledger?asset_type_id=$ASSET_TYPE_ID&after_id=$PAYMENT_LEDGER_CURSOR&limit=100" | jqFor every response:
- Upsert items idempotently by
deposit_id,withdrawal_id, orledger_id. - Save
next_cursorin the same database transaction where possible. - Continue immediately while
has_moreistrue. - Resume from the saved cursor on the next poll.
Identify ledger references by both ref_type and ref_id. ref_type=1000 identifies a deposit; ref_type=2000 identifies a withdrawal or internal transfer. amount_raw is an absolute value: apply its direction using entry_type, and distinguish principal and fee entries with entry_code. Use balance_after_raw when comparing ledger totals to balances.
ID cursors return newly created records, not later status changes. Poll non-final deposits and withdrawals by their detail endpoints until each reaches a final state. The append-only ledger can be synchronized only by cursor.