English
Request an External Withdrawal
External withdrawal is asynchronous. Validate the destination and quote before creating a request, then track the result separately.
Validate the destination address
Use an external testnet address for this tutorial. If the address belongs to another OOLIN account, the server may classify the movement 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" | jqContinue only when data.is_valid is true.
Request a quote
bash
quote_body="$(jq -nc \
--argjson account_id "$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" | jqRequire can_withdraw: true and transfer_type: "EXTERNAL". Show the customer the fee, receive amount, and applicable minimum or maximum before confirmation.
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 withdrawal
Generate one globally unique client_request_id and persist it before submission.
bash
export WITHDRAWAL_REQUEST_ID="withdrawal-$(node -e 'process.stdout.write(require("crypto").randomUUID())')"
withdrawal_body="$(jq -nc \
--argjson account_id "$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 "$WITHDRAWAL_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")"
printf '%s\n' "$withdrawal_response" | jq
export WITHDRAWAL_ID="$(printf '%s' "$withdrawal_response" | jq -r '.data.withdrawal_id')"Confirm request_type: "EXTERNAL". At creation, the withdrawal amount and fee move from available balance into the pending withdrawal balance. This reservation is not on-chain completion.
If the create response is lost, recover the existing result before attempting another request:
bash
wallet_request GET "/withdrawals/client-request/$WITHDRAWAL_REQUEST_ID" | jqAfter a successful recovery, store the returned withdrawal_id as WITHDRAWAL_ID and continue status polling. A single WITHDRAWAL_NOT_FOUND does not prove the request was never processed; recover with the original ID according to the idempotency guide.
Next: Track withdrawal status.