SSeev PlusDocs
Stellar Anchor

SEP-6: Deposit (GHS → USDC)

On-ramp Ghana Cedis to USDC via Mobile Money using the SEP-6 deposit API.

A deposit converts GHS (Ghana Cedis) to USDC on the Stellar network. The customer pays via Mobile Money and receives USDC in their Stellar wallet. This page covers the full programmatic SEP-6 deposit flow.

Flow overview

Client                    Anchor                    MoMo Gateway     Stellar
  │                         │                           │              │
  │  GET /sep6/deposit      │                           │              │
  │────────────────────────►│                           │              │
  │  { id, extra_info }     │                           │              │
  │◄────────────────────────│                           │              │
  │                         │                           │              │
  │                         │  Collect GHS (auto)       │              │
  │                         │──────────────────────────►│              │
  │                         │  Payment confirmed        │              │
  │                         │◄──────────────────────────│              │
  │                         │                           │              │
  │                         │  Send USDC                │              │
  │                         │──────────────────────────────────────────►│
  │                         │                           │              │
  │  on_change_callback     │                           │              │
  │◄────────────────────────│                           │              │

Prerequisites

  1. Valid SEP-10 JWT token (Authentication)
  2. KYC status is ACCEPTED (KYC)
  3. Stellar account has a USDC trustline established

Step 1: Check anchor capabilities

curl -X GET "https://<your-anchor-domain>/sep6/info" \
  -H "Authorization: Bearer <sep10_jwt_token>"
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');

// Authenticate
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });

// Get SEP-6 info
const sep6 = anchor.sep6();
const info = await sep6.info();
console.log("Deposit assets:", info.deposit);
console.log("USDC min:", info.deposit.USDC.min_amount);
console.log("USDC max:", info.deposit.USDC.max_amount);

Response:

{
  "deposit": {
    "USDC": {
      "enabled": true,
      "min_amount": 1,
      "max_amount": 10000,
      "funding_methods": ["mobile"],
      "fields": {
        "funding_method": {
          "description": "Payment method",
          "choices": ["mobile"]
        }
      }
    }
  },
  "withdraw": {
    "USDC": {
      "enabled": true,
      "min_amount": 1,
      "max_amount": 10000
    }
  },
  "fee": {
    "enabled": true
  },
  "features": {
    "account_creation": false,
    "claimable_balances": false
  }
}

Step 2: Initiate a deposit

The amount parameter represents the USDC amount you want to receive. The anchor calculates the equivalent GHS the customer needs to pay based on the current exchange rate.

curl -X GET "https://<your-anchor-domain>/sep6/deposit?\
asset_code=USDC&\
account=GCEXAMPLE4KEYPAIR7HERE2REPLACE5WITH5YOUR5ACTUAL5STELLAR5KEY&\
amount=6.5&\
funding_method=mobile&\
on_change_callback=https://yourapp.com/webhooks/anchor" \
  -H "Authorization: Bearer <sep10_jwt_token>"
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');

// Authenticate
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });

// Initiate deposit
const sep6 = anchor.sep6();
const deposit = await sep6.deposit({
  authToken,
  params: {
    asset_code: 'USDC',
    account: accountKp.publicKey,
    amount: '6.5',
    funding_method: 'mobile',
  },
});

console.log("Deposit ID:", deposit.id);

Parameters

ParameterRequiredDescription
asset_codeYesAsset to deposit — USDC
accountYesStellar public key to receive USDC
amountNoAmount of USDC to receive (anchor converts to GHS)
funding_methodNoPayment method — mobile for Mobile Money
on_change_callbackNoURL to receive transaction status updates
memoNoMemo to attach to the Stellar payment
memo_typeNoMemo type: text, id, or hash

Auto vs Manual collection modes

Auto collection

When the anchor can automatically collect via STK push:

{
  "id": "txn_8f3a4b2c-1d5e-6f7a-8b9c-0d1e2f3a4b5c",
  "how": "mobile_money",
  "extra_info": {
    "message": "A Mobile Money prompt will be sent to +233241234567. Approve the payment of GHS 100.00 to complete your deposit of 6.50 USDC."
  },
  "min_amount": "1",
  "max_amount": "10000",
  "eta": 300
}

In auto mode, the anchor sends an STK push (payment prompt) directly to the customer's registered Mobile Money number. The customer approves the prompt on their phone.

Manual collection

When auto-collection is not available:

{
  "id": "txn_8f3a4b2c-1d5e-6f7a-8b9c-0d1e2f3a4b5c",
  "how": "mobile_money",
  "instructions": {
    "network": "MTN",
    "short_code": "*170#",
    "recipient": "0241000000",
    "reference": "SEEV-DEP-8F3A4B",
    "amount": "GHS 100.00"
  },
  "min_amount": "1",
  "max_amount": "10000",
  "eta": 600
}

In manual mode, the customer must initiate the payment themselves using the provided instructions.

Amount handling

You sendMeaning
amount=6.5You want to receive 6.5 USDC. Anchor calculates GHS equivalent (~100 GHS at rate 15.38 GHS/USDC).
No amountAnchor returns min/max. Customer decides how much GHS to send.

The exchange rate includes the anchor's fee. Use SEP-38 Quotes to lock in a rate before initiating the deposit.

Step 3: Poll transaction status

curl -X GET "https://<your-anchor-domain>/sep6/transaction?id=txn_8f3a4b2c-1d5e-6f7a-8b9c-0d1e2f3a4b5c" \
  -H "Authorization: Bearer <sep10_jwt_token>"
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 });

// Use the watcher for real-time transaction tracking
const sep6 = anchor.sep6();
const watcher = sep6.watcher();

const { stop, refresh } = watcher.watchOneTransaction({
  authToken,
  assetCode: 'USDC',
  id: 'txn_8f3a4b2c-1d5e-6f7a-8b9c-0d1e2f3a4b5c',
  onMessage: (txn) => console.log(`Status: ${txn.status}`),
  onSuccess: (txn) => {
    console.log(`Received ${txn.amount_out} USDC`);
    console.log(`Stellar tx: ${txn.stellar_transaction_id}`);
  },
  onError: (err) => console.error('Error:', err),
});

// Or get a single transaction
const { transaction } = await sep6.getTransactionBy({
  authToken,
  id: 'txn_8f3a4b2c-1d5e-6f7a-8b9c-0d1e2f3a4b5c',
});
console.log(`Status: ${transaction.status}`);

Response (pending):

{
  "transaction": {
    "id": "txn_8f3a4b2c-1d5e-6f7a-8b9c-0d1e2f3a4b5c",
    "kind": "deposit",
    "status": "pending_user_transfer_start",
    "status_eta": 300,
    "amount_in": "100.00",
    "amount_in_asset": "iso4217:GHS",
    "amount_out": "6.50",
    "amount_out_asset": "stellar:USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
    "amount_fee": "0.10",
    "amount_fee_asset": "stellar:USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
    "started_at": "2026-08-05T01:15:00Z",
    "more_info_url": "https://<your-anchor-domain>/more-info/txn_8f3a4b2c"
  }
}

Response (completed):

{
  "transaction": {
    "id": "txn_8f3a4b2c-1d5e-6f7a-8b9c-0d1e2f3a4b5c",
    "kind": "deposit",
    "status": "completed",
    "amount_in": "100.00",
    "amount_in_asset": "iso4217:GHS",
    "amount_out": "6.50",
    "amount_out_asset": "stellar:USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
    "amount_fee": "0.10",
    "amount_fee_asset": "stellar:USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
    "started_at": "2026-08-05T01:15:00Z",
    "completed_at": "2026-08-05T01:19:30Z",
    "stellar_transaction_id": "abc123def456...",
    "more_info_url": "https://<your-anchor-domain>/more-info/txn_8f3a4b2c"
  }
}

on_change_callback

If you provided an on_change_callback URL, the anchor POSTs status updates to it:

{
  "transaction": {
    "id": "txn_8f3a4b2c-1d5e-6f7a-8b9c-0d1e2f3a4b5c",
    "status": "completed",
    "stellar_transaction_id": "abc123def456..."
  }
}

Do not rely solely on callbacks — always verify transaction status by polling. Callbacks are best-effort and may be delayed or missed.

Deposit status flow

pending_user_transfer_start  →  User needs to approve/send MoMo payment
pending_anchor               →  Anchor received GHS, processing USDC send
completed                    →  USDC sent to customer's Stellar address
error                        →  Something went wrong (check message)
expired                      →  Deposit window expired without payment

See Transactions for the full status lifecycle.

Full TypeScript example

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');

async function deposit() {
  // Step 1: Authenticate
  const sep10 = await anchor.sep10();
  const authToken = await sep10.authenticate({ accountKp });

  // Step 2: Initiate deposit of 6.5 USDC (≈ GHS 100)
  const sep6 = anchor.sep6();
  const deposit = await sep6.deposit({
    authToken,
    params: {
      asset_code: 'USDC',
      account: accountKp.publicKey,
      amount: '6.5',
      funding_method: 'mobile',
    },
  });

  console.log("Deposit initiated:", deposit.id);

  // Step 3: Watch for completion using the watcher
  const watcher = sep6.watcher();
  const { stop } = watcher.watchOneTransaction({
    authToken,
    assetCode: 'USDC',
    id: deposit.id,
    onMessage: (txn) => {
      console.log(`Status: ${txn.status}`);
      if (txn.status === 'pending_user_transfer_start') {
        console.log('Approve the Mobile Money prompt on your phone.');
      }
    },
    onSuccess: (txn) => {
      console.log(`Received ${txn.amount_out} USDC`);
      console.log(`Stellar tx: ${txn.stellar_transaction_id}`);
      stop();
    },
    onError: (err) => {
      console.error('Deposit error:', err);
      stop();
    },
  });
}

await deposit();

Establishing a USDC trustline

Before the anchor can send USDC to your account, you must trust the USDC asset:

import { Wallet, Keypair } from '@stellar/typescript-wallet-sdk';

const wallet = Wallet.TestNet();
const accountKp = Keypair.fromSecret('SCZANGBA5YHTNYVVV3C7CAZMCLXPJLNS2YFGXDNASLFTGBPFMRKCY6ML');

// The wallet SDK's stellar module handles trustline operations
const stellar = wallet.stellar();
const txBuilder = await stellar.transaction({ sourceAddress: accountKp });

// Add USDC trustline
const USDC_ISSUER = 'GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5';
txBuilder.addAssetSupport(new IssuedAssetId('USDC', USDC_ISSUER));

const tx = txBuilder.build();
tx.sign(accountKp);
await stellar.submitTransaction(tx);
console.log("USDC trustline established");

Error responses

StatusErrorMeaning
400invalid_amountAmount outside min/max range
400invalid_asset_codeAsset not supported
403kyc_requiredKYC not yet approved
403customer_info_neededAdditional KYC fields required
429rate_limitToo many requests
500internal_errorAnchor-side error — retry later

On this page