SEP-24: Interactive Deposit & Withdrawal
Use the anchor-hosted interactive UI for deposit and withdrawal flows via SEP-24.
SEP-24 provides an interactive, anchor-hosted UI for deposits and withdrawals. Unlike SEP-6 (where the wallet handles all UX), SEP-24 opens a popup or webview where the anchor collects KYC and payment details directly from the user.
SeevCash supports both SEP-6 (programmatic) and SEP-24 (interactive). Choose SEP-6 for API-driven integrations and SEP-24 for simple wallet integrations that want the anchor to handle the UI.
When to use SEP-24 vs SEP-6
| SEP-6 | SEP-24 | |
|---|---|---|
| UI | Wallet handles all UI | Anchor provides popup/webview |
| KYC | Wallet submits KYC via SEP-12 API | Anchor collects in hosted form |
| Best for | API integrations, automated systems | Simple wallets, MoneyGram flows |
| Complexity | More code, full control | Less code, less control |
Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
GET | /sep24/info | No | Service info and supported assets |
POST | /sep24/transactions/deposit/interactive | JWT | Start interactive deposit |
POST | /sep24/transactions/withdraw/interactive | JWT | Start interactive withdrawal |
GET | /sep24/transaction | JWT | Get transaction status |
GET | /sep24/transactions | JWT | List transaction history |
Flow overview
Wallet Anchor User
│ │ │
│ POST /deposit/interactive │
│────────────────────────►│ │
│ { url, id } │ │
│◄────────────────────────│ │
│ │ │
│ Open URL in popup │ │
│─────────────────────────────────────────────────►│
│ │ │
│ │ User fills KYC form │
│ │◄────────────────────────│
│ │ User enters MoMo info │
│ │◄────────────────────────│
│ │ │
│ Poll GET /transaction │ │
│────────────────────────►│ │
│ { status: completed } │ │
│◄────────────────────────│ │Interactive deposit (GHS → USDC)
Step 1: Start the interactive flow
curl -X POST "https://<your-anchor-domain>/sep24/transactions/deposit/interactive" \
-H "Authorization: Bearer <sep10_jwt>" \
-H "Content-Type: application/json" \
-d '{
"asset_code": "USDC",
"account": "GA2E5D24D2LCGVA3SVVKDP64OTN2M2NLUWRDYINB352HW35ABZ66MPVR"
}'import { Wallet, Keypair } from '@stellar/typescript-wallet-sdk';
const wallet = Wallet.TestNet();
const anchor = wallet.anchor({ homeDomain: '<your-anchor-domain>' });
const accountKp = Keypair.fromSecret('SCZANGBA5YHTNYVVV3C7CAZMCLXPJLNS2YFGXDNASLFTGBPFMRKCY6ML');
// Authenticate
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });
// Start interactive deposit via SEP-24
const sep24 = anchor.sep24();
const { url, id } = await sep24.deposit({
authToken,
params: {
asset_code: 'USDC',
account: accountKp.publicKey,
},
});
// Open url in popup/webview for user to complete
console.log("Interactive URL:", url);
console.log("Transaction ID:", id);Response:
{
"type": "interactive_customer_info_needed",
"url": "https://<your-anchor-domain>/sep24/interactive?token=abc123&transaction_id=txn-456",
"id": "txn-456"
}Step 2: Open the URL
The wallet opens the returned url in a popup, iframe, or webview. The user completes:
- KYC information (name, phone, ID)
- Mobile money details (phone number, provider)
- Amount confirmation
Step 3: Poll for completion
curl -X GET "https://<your-anchor-domain>/sep24/transaction?id=txn-456" \
-H "Authorization: Bearer <sep10_jwt>"import { Wallet, Keypair } from '@stellar/typescript-wallet-sdk';
const wallet = Wallet.TestNet();
const anchor = wallet.anchor({ homeDomain: '<your-anchor-domain>' });
const accountKp = Keypair.fromSecret('SCZANGBA5YHTNYVVV3C7CAZMCLXPJLNS2YFGXDNASLFTGBPFMRKCY6ML');
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });
const sep24 = anchor.sep24();
const { transaction } = await sep24.getTransactionBy({
authToken,
id: 'txn-456',
});
console.log('Status:', transaction.status);Response (in progress):
{
"transaction": {
"id": "txn-456",
"kind": "deposit",
"status": "pending_user_transfer_start",
"more_info_url": "https://<your-anchor-domain>/sep24/transaction/more_info?id=txn-456"
}
}Response (completed):
{
"transaction": {
"id": "txn-456",
"kind": "deposit",
"status": "completed",
"amount_in": "100.00",
"amount_out": "6.50",
"stellar_transaction_id": "abc123def...",
"completed_at": "2026-08-05T01:00:00Z"
}
}Interactive withdrawal (USDC → GHS)
Step 1: Start the interactive flow
curl -X POST "https://<your-anchor-domain>/sep24/transactions/withdraw/interactive" \
-H "Authorization: Bearer <sep10_jwt>" \
-H "Content-Type: application/json" \
-d '{
"asset_code": "USDC",
"account": "GA2E5D24D2LCGVA3SVVKDP64OTN2M2NLUWRDYINB352HW35ABZ66MPVR"
}'import { Wallet, Keypair } from '@stellar/typescript-wallet-sdk';
const wallet = Wallet.TestNet();
const anchor = wallet.anchor({ homeDomain: '<your-anchor-domain>' });
const accountKp = Keypair.fromSecret('SCZANGBA5YHTNYVVV3C7CAZMCLXPJLNS2YFGXDNASLFTGBPFMRKCY6ML');
// Authenticate
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });
// Start interactive withdrawal via SEP-24
const sep24 = anchor.sep24();
const { url, id } = await sep24.withdraw({
authToken,
params: {
asset_code: 'USDC',
account: accountKp.publicKey,
},
});
// Open url in popup/webview for user to complete
console.log("Interactive URL:", url);
console.log("Transaction ID:", id);Response:
{
"type": "interactive_customer_info_needed",
"url": "https://<your-anchor-domain>/sep24/interactive?token=def789&transaction_id=txn-789",
"id": "txn-789"
}Step 2: User completes the form
In the interactive UI, the user:
- Enters the amount of USDC to withdraw
- Provides mobile money payout details
- Confirms the exchange rate
Step 3: Send USDC
After the interactive form is complete, the transaction status changes to pending_user_transfer_start. The wallet must send USDC to the anchor:
import { Wallet, Keypair } from '@stellar/typescript-wallet-sdk';
import {
Asset,
TransactionBuilder,
Networks,
Horizon,
Operation,
Memo,
} from '@stellar/stellar-sdk';
const wallet = Wallet.TestNet();
const anchor = wallet.anchor({ homeDomain: '<your-anchor-domain>' });
const accountKp = Keypair.fromSecret('SCZANGBA5YHTNYVVV3C7CAZMCLXPJLNS2YFGXDNASLFTGBPFMRKCY6ML');
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });
// Get transaction details for withdraw_anchor_account and memo
const sep24 = anchor.sep24();
const { transaction } = await sep24.getTransactionBy({ authToken, id: 'txn-789' });
const server = new Horizon.Server('https://horizon-testnet.stellar.org');
const account = await server.loadAccount(accountKp.publicKey);
const tx = new TransactionBuilder(account, {
fee: '100',
networkPassphrase: Networks.TESTNET,
})
.addOperation(Operation.payment({
destination: transaction.withdraw_anchor_account,
asset: new Asset('USDC', 'GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5'),
amount: transaction.amount_in,
}))
.addMemo(Memo.text(transaction.withdraw_memo))
.setTimeout(300)
.build();
tx.sign(accountKp);
await server.submitTransaction(tx);Step 4: Poll for completion
The anchor detects the incoming USDC payment, converts to GHS, and pays out via Mobile Money.
curl -X GET "https://<your-anchor-domain>/sep24/transaction?id=txn-789" \
-H "Authorization: Bearer <sep10_jwt>"import { Wallet, Keypair } from '@stellar/typescript-wallet-sdk';
const wallet = Wallet.TestNet();
const anchor = wallet.anchor({ homeDomain: '<your-anchor-domain>' });
const accountKp = Keypair.fromSecret('SCZANGBA5YHTNYVVV3C7CAZMCLXPJLNS2YFGXDNASLFTGBPFMRKCY6ML');
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });
const sep24 = anchor.sep24();
const { transaction } = await sep24.getTransactionBy({
authToken,
id: 'txn-789',
});
console.log('Status:', transaction.status);
// terminal statuses: completed, error, expired, refunded{
"transaction": {
"id": "txn-789",
"kind": "withdrawal",
"status": "completed",
"amount_in": "50.00",
"amount_out": "665.00",
"stellar_transaction_id": "xyz789...",
"external_transaction_id": "PROV-456",
"completed_at": "2026-08-05T01:05:00Z"
}
}TypeScript integration
import { Wallet, Keypair } from '@stellar/typescript-wallet-sdk';
const wallet = Wallet.TestNet();
const ANCHOR_HOME_DOMAIN = '<your-anchor-domain>';
const anchor = wallet.anchor({ homeDomain: ANCHOR_HOME_DOMAIN });
const accountKp = Keypair.fromSecret('SCZANGBA5YHTNYVVV3C7CAZMCLXPJLNS2YFGXDNASLFTGBPFMRKCY6ML');
// 1. Authenticate (SEP-10)
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });
// 2. Start interactive deposit (SEP-24)
const sep24 = anchor.sep24();
const { url, id } = await sep24.deposit({
authToken,
params: {
asset_code: 'USDC',
account: accountKp.publicKey,
},
});
// 3. Open the URL in a popup/webview
window.open(url, '_blank', 'width=450,height=700');
// 4. Poll for status using the watcher
const watcher = sep24.watcher();
const { stop } = watcher.watchOneTransaction({
authToken,
assetCode: 'USDC',
id,
onMessage: (txn) => console.log('Status:', txn.status),
onSuccess: (txn) => {
console.log('Deposit complete! Stellar TX:', txn.stellar_transaction_id);
stop();
},
onError: (err) => {
console.error('Error:', err);
stop();
},
});SEP-6 vs SEP-24 comparison
| Feature | SEP-6 (Programmatic) | SEP-24 (Interactive) |
|---|---|---|
| KYC collection | Wallet → SEP-12 API | Anchor's hosted form |
| Payment details | Wallet shows instructions | Anchor's hosted form |
| Mobile money trigger | Anchor auto-collects (auto mode) | Anchor handles in form |
| Integration effort | More code | Less code (just open URL) |
| User experience control | Wallet controls UX | Anchor controls UX |
| MoneyGram support | ❌ | ✅ |
Related
- Deposit via SEP-6 — Programmatic deposit without interactive UI
- Withdrawal via SEP-6 — Programmatic withdrawal
- Authentication — Required before starting any flow
- Stellar SEP-24 Specification