> ## Documentation Index
> Fetch the complete documentation index at: https://developers.circle.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Before reading these docs, install the relevant Circle Skill to get pre-loaded context — skills are LLM-optimized and cover architecture decisions, correct flows, and common pitfalls. In Claude Code: run /plugin marketplace add circlefin/skills then /plugin install circle-skills@circle. With Vercel Skills CLI: run npx skills add circlefin/skills. Available skills: use-usdc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-usdc/SKILL.md (balances, transfers, approvals on EVM and Solana); EURC has no skill — see https://developers.circle.com/stablecoins/what-is-eurc.md; bridge-stablecoin https://github.com/circlefin/skills/blob/master/plugins/circle/skills/bridge-stablecoin/SKILL.md (crosschain transfers via CCTP, USDC, EURC, and third-party assets); use-arc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-arc/SKILL.md (Arc chain config, contract deployment, USDC bridging — Arc docs: https://docs.arc.io/llms.txt); use-circle-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-circle-wallets/SKILL.md (choose wallet type); use-developer-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-developer-controlled-wallets/SKILL.md (custodial wallets for payouts and treasury); use-user-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-user-controlled-wallets/SKILL.md (embedded wallets with Web2 login); use-modular-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-modular-wallets/SKILL.md (smart contract wallets with passkeys and ERC-4337); use-gateway https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-gateway/SKILL.md (unified USDC balance, nanopayments); use-smart-contract-platform https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-smart-contract-platform/SKILL.md (deploy, interact, monitor contracts). Pair any skill with the Circle MCP server for live SDK signatures, contract addresses, and chain IDs: {"mcpServers":{"circle":{"url":"https://api.circle.com/v1/codegen/mcp"}}}.
> Read the product overview first. Each product has an overview explaining when and why to use it. Read it before quickstarts.
> Pick the right wallet type. Developer-controlled (you hold keys), user-controlled (end user holds keys via PIN/social login), or modular (smart contract wallets with passkeys). See https://developers.circle.com/wallets.md.
> Use CCTP V2 for crosschain transfers. CCTP natively transfers USDC and EURC via burn-and-mint, and supports permissionless wrapping of third-party assets via lock-and-mint. V1 is legacy; always use V2 unless V1 is specified or the chain requires it (Noble, Sui, and Aptos still require V1). Migration guide: https://developers.circle.com/cctp/migration-from-v1-to-v2.md.
> Use Bridge Kit for frontend bridging. Wraps CCTP with a simpler SDK for user-facing apps. Use CCTP directly for backend transfers.
> Gas Station vs Paymaster. Gas Station sponsors gas for Circle Wallet transactions. Paymaster lets users pay gas in USDC. Different use cases — read both overviews.
> Gateway Nanopayments for sub-cent payments. Gasless USDC micropayments down to $0.000001 via x402 and batched settlement. For pay-per-request APIs, AI agent payments, streaming.
> Look up USDC addresses per chain. Never hardcode — use https://developers.circle.com/stablecoins/usdc-contract-addresses.md.
> Prefer SDKs over raw API calls. Node.js and Python SDKs handle auth, retries, and errors.
> API key required. Bearer token in Authorization header. Testnet and mainnet use separate keys and may use different base URLs depending on the product.
> Set up webhooks when available. Most operations are async. Webhooks deliver transaction confirmations and state changes.
> When calling list endpoints, paginate using pageSize and pageAfter until no nextPageAfter cursor is returned—stopping at the first page silently misses records.
> Building an AI agent? Start with the Agent Stack—Circle CLI, agent wallets, and nanopayments built for autonomous use cases: https://developers.circle.com/agent-stack.md.

# Quickstart: Transfer USDC on Stellar

> Send USDC between accounts on Stellar Testnet using the Stellar SDK.

USDC on Stellar is a native asset issued by Circle. Transferring USDC between
Stellar accounts uses a standard payment operation, submitted through
[Horizon](https://developers.stellar.org/docs/data/apis/horizon), Stellar's HTTP
API for submitting transactions. To transfer USDC crosschain between Stellar and
other blockchains, see
[Transfer USDC between Stellar and Arc](/cctp/quickstarts/transfer-usdc-stellar-arc).

The [`@stellar/stellar-sdk`](https://github.com/stellar/js-stellar-sdk) script
you build in this guide will:

* Create and fund a recipient Stellar Testnet wallet
* Establish a USDC trustline on the recipient account
* Transfer USDC from your existing sender wallet to the recipient

<Note>
  Before a Stellar account can receive USDC, it must establish a trustline for the
  asset. See
  [Set up a USDC trustline on Stellar](/stablecoins/quickstart-setup-usdc-trustline-stellar)
  for more detail. This quickstart handles trustline setup automatically as part
  of the script.
</Note>

## Prerequisites

Before you begin, ensure that you have:

* Installed [Node.js v22.6+](https://nodejs.org/)
* Set up a terminal and code editor for running commands and editing files
* Created a Stellar Testnet wallet with the secret key (`S...`) available
  * Funded with testnet XLM (for transaction fees) from
    [Stellar Friendbot](https://lab.stellar.org/account/fund)
  * Funded with testnet USDC from the [Circle Faucet](https://faucet.circle.com)

## Contract addresses

You need the following Stellar Testnet USDC issuer address:

* Testnet:
  [`GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5`](https://stellar.expert/explorer/testnet/asset/USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5)

## Step 1: Set up the project

### 1.1. Create the project and install dependencies

Create a new directory and install the required dependencies:

```bash Shell theme={null}
# Set up your directory and initialize a Node.js project
mkdir stellar-usdc-transfer
cd stellar-usdc-transfer
npm init -y

# Set up module type and start command
npm pkg set type=module
npm pkg set scripts.start="node --env-file=.env main.ts"

# Install runtime dependencies
npm install @stellar/stellar-sdk

# Install dev dependencies
npm install --save-dev typescript @types/node
```

### 1.2. Configure TypeScript (optional)

<Tip>
  This step is optional. It helps prevent missing types in your IDE or editor.
</Tip>

Create a `tsconfig.json` file:

```shell theme={null}
npx tsc --init
```

Then, update the `tsconfig.json` file:

```shell theme={null}
cat <<'EOF' > tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "types": ["node"]
  }
}
EOF
```

### 1.3. Configure environment variables

Create a `.env` file in your project directory and add your sender's secret key:

```text .env theme={null}
STELLAR_SECRET_KEY=YOUR_SENDER_SECRET_KEY
```

<Tip>
  Open `.env` in your editor rather than writing values with shell commands, and
  add `.env` to your `.gitignore`. This prevents credentials from leaking into
  your shell history or version control.
</Tip>

<Warning>
  This example uses one or more private keys for local testing. In production,
  use a secure key management solution and never expose or share private keys.
</Warning>

## Step 2: Create the transfer script

Add `main.ts` at the project root. The script:

1. Loads your existing sender wallet from the environment variable
2. Creates and funds a new recipient wallet using Friendbot
3. Establishes a USDC trustline on the recipient account
4. Submits a USDC payment from the sender to the recipient

```typescript main.ts theme={null}
import {
  Asset,
  BASE_FEE,
  Horizon,
  Keypair,
  Networks,
  Operation,
  TransactionBuilder,
} from "@stellar/stellar-sdk";

const HORIZON_URL = "https://horizon-testnet.stellar.org";
const FRIENDBOT_URL = "https://friendbot.stellar.org";
const USDC_ISSUER = "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5";
const USDC_CODE = "USDC";
const TRANSFER_AMOUNT = "10"; // 10 USDC
const TX_EXPLORER_BASE = "https://stellar.expert/explorer/testnet/tx";

const server = new Horizon.Server(HORIZON_URL);
const usdc = new Asset(USDC_CODE, USDC_ISSUER);

async function fundWithFriendbot(publicKey: string): Promise<void> {
  const response = await fetch(`${FRIENDBOT_URL}?addr=${publicKey}`);
  if (!response.ok) {
    throw new Error(
      `Friendbot funding failed: ${response.status} ${response.statusText}`,
    );
  }
}

async function establishTrustline(keypair: Keypair): Promise<void> {
  const account = await server.loadAccount(keypair.publicKey());
  const tx = new TransactionBuilder(account, {
    fee: BASE_FEE,
    networkPassphrase: Networks.TESTNET,
  })
    .addOperation(Operation.changeTrust({ asset: usdc }))
    .setTimeout(30)
    .build();

  tx.sign(keypair);
  const result = await server.submitTransaction(tx);
  if (!result.successful) {
    throw new Error(`Trustline transaction failed: ${JSON.stringify(result)}`);
  }
  console.log(`Trustline established: ${TX_EXPLORER_BASE}/${result.hash}`);
}

async function transferUsdc(
  sender: Keypair,
  recipientPublicKey: string,
): Promise<void> {
  const account = await server.loadAccount(sender.publicKey());
  const tx = new TransactionBuilder(account, {
    fee: BASE_FEE,
    networkPassphrase: Networks.TESTNET,
  })
    .addOperation(
      Operation.payment({
        destination: recipientPublicKey,
        asset: usdc,
        amount: TRANSFER_AMOUNT,
      }),
    )
    .setTimeout(30)
    .build();

  tx.sign(sender);
  const result = await server.submitTransaction(tx);
  if (!result.successful) {
    throw new Error(`Payment transaction failed: ${JSON.stringify(result)}`);
  }
  console.log(`Transfer successful: ${TX_EXPLORER_BASE}/${result.hash}`);
}

async function main() {
  // Load the sender wallet from the environment variable
  const sender = Keypair.fromSecret(process.env.STELLAR_SECRET_KEY as string);
  console.log("Sender address:", sender.publicKey());

  // Create and fund a new recipient wallet via Friendbot
  console.log("\nCreating recipient wallet...");
  const recipient = Keypair.random();
  console.log("Recipient address:", recipient.publicKey());

  console.log("Funding recipient with testnet XLM...");
  await fundWithFriendbot(recipient.publicKey());
  console.log("Recipient funded with XLM.");

  // Establish a USDC trustline on the recipient account
  console.log("\nEstablishing USDC trustline on recipient account...");
  await establishTrustline(recipient);

  // Transfer USDC from sender to recipient
  console.log(`\nTransferring ${TRANSFER_AMOUNT} USDC to recipient...`);
  await transferUsdc(sender, recipient.publicKey());

  // Confirm recipient balance
  const recipientAccount = await server.loadAccount(recipient.publicKey());
  const usdcBalance = recipientAccount.balances.find(
    (b) =>
      b.asset_type === "credit_alphanum4" &&
      b.asset_code === USDC_CODE &&
      b.asset_issuer === USDC_ISSUER,
  );
  console.log(`\nRecipient USDC balance: ${usdcBalance?.balance ?? "0"} USDC`);
}

main().catch(console.error);
```

## Step 3: Run the script

From the project directory, run:

```bash Shell theme={null}
npm run start
```

Your output should look similar to the following (addresses and hashes will
differ):

```bash Shell theme={null}
Sender address: GAXYZ...

Creating recipient wallet...
Recipient address: GDEFG...
Funding recipient with testnet XLM...
Recipient funded with XLM.

Establishing USDC trustline on recipient account...
Trustline established: https://stellar.expert/explorer/testnet/tx/abc123...

Transferring 10 USDC to recipient...
Transfer successful: https://stellar.expert/explorer/testnet/tx/def456...

Recipient USDC balance: 10.0000000 USDC
```

<Info>
  Common errors you might encounter:

  * **`Friendbot funding failed: 400`**: The Friendbot rate limit was exceeded.
    Wait a few seconds and try again.
  * **`op_no_trust`**: The recipient account does not have a USDC trustline. The
    script establishes one automatically, but if you're adapting this example for
    your own recipient address, ensure the trustline exists first. See
    [Set up a USDC trustline on Stellar](/stablecoins/quickstart-setup-usdc-trustline-stellar).
  * **`op_underfunded`**: The sender does not have enough USDC. Ensure your sender
    wallet is funded with testnet USDC from the
    [Circle Faucet](https://faucet.circle.com) before running the script.
</Info>

For more detail on Stellar-specific USDC behavior in CCTP, including address
encoding and decimal precision, see [CCTP on Stellar](/cctp/references/stellar).
