Skip to main content

7. Test Withdrawal (Transfer) Flow

The SDK's transfer() method opens the same overlay but in payout direction — the merchant sends crypto to the user's address. Unlike pay(), funds are not transferred immediately: a REQUESTED withdrawal is created in the dashboard, and a merchant admin must approve it (with 2FA) before the on-chain transfer fires.

7-1. Call SDK transfer()

await client.transfer({
price: 1,
unit: 'usd',
successUrl: '/withdrawal/success',
failUrl: '/withdrawal/fail',
onCreateInvoice: async (params) => {
const res = await fetch('/api/create-withdrawal', {
method: 'POST',
body: JSON.stringify(params),
});
const { withdrawalId } = await res.json();
return withdrawalId;
},
});

The callback receives receiver (recipient address) instead of sender. The server hits POST /api/invoices/withdrawals and returns withdrawalId. See Server Integration → Create Withdrawal for code examples.

7-2. Verify the Request in Dashboard

Dashboard → Project → 출금 요청 (Withdrawal Request)

A new row appears with status REQUESTED. The funds have not moved on-chain yet.

7-3. Admin Approves with 2FA

The merchant admin clicks Approve on the row → 2FA prompt → confirm.

This triggers the on-chain transfer from the project wallet to the receiver. Status moves REQUESTEDPENDINGCONFIRMED once mined.

7-4. Verify the On-chain Transfer

Dashboard → Project → 거래내역 (Transactions) — the withdrawal appears as type WITHDRAWAL with the resulting TX hash.

Click the TX hash to inspect on the block explorer.

Notes

  • For testing, the merchant's project wallet must hold the token + native gas coin (e.g., USDC + ETH on Sepolia). Get it via the same faucets used for deposit testing, but send to the project wallet's address (visible on the project home).
  • 2FA is required for approval — set up TOTP for the admin user beforehand.
  • Bulk approval works the same way; multiple REQUESTED rows can be approved at once.