English
Settle to an External Address
External settlement sends funds accumulated in the merchant payment account to an address on the selected network. This is asynchronous: OOLIN validates the request, processes the on-chain transfer, and reflects the final result in the Wallet API.
text
Customer backend → create withdrawal → request processing
→ on-chain transfer → retrieve Wallet API resultYour backend creates the withdrawal through the Wallet API and retrieves its detail to confirm the final result.
Validate the destination and request a quote
Use a valid external Sepolia address. An address managed as another OOLIN account's deposit address may cause the request to be classified as an internal transfer.
bash
export TO_ADDRESS='{valid-testnet-address}'
export WITHDRAW_AMOUNT='1.00'
asset_response="$(
wallet_request GET "/assets/by-type-network?asset_type_id=$ASSET_TYPE_ID&network_id=$NETWORK_ID"
)"
export ASSET_ID="$(printf '%s' "$asset_response" | jq -r '.data.asset_id')"
validate_body="$(jq -nc --arg address "$TO_ADDRESS" '{address:$address}')"
wallet_request POST "/assets/$ASSET_ID/validate-address" "$validate_body" | jqWhen data.is_valid is true, request a quote.
bash
quote_body="$(jq -nc \
--argjson account_id "$PAYMENT_ACCOUNT_ID" \
--argjson asset_type_id "$ASSET_TYPE_ID" \
--arg amount "$WITHDRAW_AMOUNT" \
--arg to_address "$TO_ADDRESS" \
--argjson network_id "$NETWORK_ID" \
'{account_id:$account_id,asset_type_id:$asset_type_id,amount:$amount,to_address:$to_address,network_id:$network_id}')"
wallet_request POST '/withdrawals/quote' "$quote_body" | jqProceed only when can_withdraw is true and transfer_type is EXTERNAL. Review the fee, receive amount, and limits.
The reserved and debited account amount is amount + fee_amount; receive_amount is the recipient amount. A quote neither reserves funds nor guarantees success, so handle errors during creation as well.
Create the external withdrawal
Persist SETTLEMENT_REQUEST_ID with the settlement operation, amount, and destination before sending the request. Use the stored ID during recovery rather than generating another ID for the same settlement.
bash
export SETTLEMENT_REQUEST_ID="settlement-$(node -e 'process.stdout.write(require("crypto").randomUUID())')"
withdrawal_body="$(jq -nc \
--argjson account_id "$PAYMENT_ACCOUNT_ID" \
--argjson asset_type_id "$ASSET_TYPE_ID" \
--arg amount "$WITHDRAW_AMOUNT" \
--arg to_address "$TO_ADDRESS" \
--argjson network_id "$NETWORK_ID" \
--arg client_request_id "$SETTLEMENT_REQUEST_ID" \
'{account_id:$account_id,asset_type_id:$asset_type_id,amount:$amount,to_address:$to_address,network_id:$network_id,client_request_id:$client_request_id}')"
withdrawal_response="$(wallet_request POST '/withdrawals' "$withdrawal_body")"
export WITHDRAWAL_ID="$(printf '%s' "$withdrawal_response" | jq -r '.data.withdrawal_id')"
printf '%s\n' "$withdrawal_response" | jqConfirm the response has request_type: "EXTERNAL". Creation reserves the amount and fee in pending_withdraw_amount_raw; it does not mean the on-chain transaction is complete.
If the create response is lost, recover with the lookup below and store the returned withdrawal_id as WITHDRAWAL_ID. A single WITHDRAWAL_NOT_FOUND does not prove the request was never processed; follow the idempotency guide.
bash
wallet_request GET "/withdrawals/client-request/$SETTLEMENT_REQUEST_ID" | jqTrack the final result
bash
wallet_request GET "/withdrawals/$WITHDRAWAL_ID" | jquser_status | Meaning | Backend action |
|---|---|---|
PENDING | Request accepted and inspected | Poll at a bounded interval |
PROCESSING | Approval or on-chain transfer processing | Keep the settlement pending |
COMPLETED | On-chain withdrawal completed | Store tx_hash and completed_at |
FAILED | On-chain processing failed | Record failure and verify balance recovery |
REJECTED | Processing rejected | Record the reason and escalate operationally |
CANCELLED | Request cancelled | Close the request and verify balance |
Final success requires user_status: "COMPLETED", status: "COMPLETED", and a valid tx_hash.
Next: Collect and recover funds.