---
title: "Send USDC to another network"
description: "Move USDC from a Gravv wallet on one network to an outside address or another Gravv wallet on a different network."
---
Use this recipe to move USDC from a Gravv wallet on one network to an outside address, or to another Gravv wallet, on a different network.

**Who it is for.** A payroll platform that holds USDC on Polygon and pays a contractor who wants USDC on Solana.

**Status.** Not yet available. Ask support to confirm it is switched on for your business. Sending USDT across networks is not supported.

## Money example

1. The Polygon wallet holds 2,000.00 USDC.
2. You send 1,000.00 USDC from it to the contractor's Solana address.
3. The USDC moves between networks without a swap, so no price applies. Read any fee in the `fee` field of the transfer response.

## Before you start

- The source wallet is a Gravv wallet (`internal_crypto_wallet`) on polygon, ethereum, solana or stellar, and it holds USDC ([`GET /v1/wallets/{wallet_id}`](/api-reference/wallets/get-v1-wallets-wallet-id)).
- The receiving side is on polygon, ethereum, solana, stellar or avalanche, and receives **USDC**.
- A Stellar receiver must already accept USDC. This is a one-time "trustline" setting in the receiving wallet.

## Find out what is required

Gravv supports only the networks listed above. The address must match its network:

- EVM networks (polygon, ethereum, avalanche) take `0x` and 40 hex characters.
- Solana takes a base58 address.
- Stellar takes a `G…` account. Gravv refuses a muxed `M…` address.

If the format is wrong, the transfer call refuses it and names the network.

## Steps

### 1. Send

<CodeGroup>
```bash title="cURL"
curl --request POST \
     --url https://api.gravv.xyz/v1/transfer \
     --header 'Api-Key: <API_KEY>' \
     --header 'Content-Type: application/json' \
     --header 'Idempotency-Key: f207b686-1dd1-4bf2-8b4e-6442681aa37f' \
     --data '
{
  "customer_id": "c7ae0522-6a4d-476f-a43c-5a9aac863c31",
  "source": {
    "source_type": "internal_crypto_wallet",
    "id": "b6705e3a-3c6c-49b0-b24f-d55aafd03635",
    "crypto_asset": "USDC"
  },
  "destination": {
    "destination_type": "crypto_wallet",
    "wallet_address": "76YbQbwcPcp8MTy6pP8efkicPhTUfYYxeEPuCQmo46K1",
    "blockchain_network": "solana"
  },
  "amount": "1000.00",
  "description": "October contract",
  "client_reference": "pay-ctr-1009"
}
'
```
```javascript title="Node"
const response = await fetch("https://api.gravv.xyz/v1/transfer", {
  method: "POST",
  headers: {
    "Api-Key": process.env.GRAVV_API_KEY,
    "Content-Type": "application/json",
    "Idempotency-Key": "f207b686-1dd1-4bf2-8b4e-6442681aa37f",
  },
  body: JSON.stringify({
    "customer_id": "c7ae0522-6a4d-476f-a43c-5a9aac863c31",
    "source": {
      "source_type": "internal_crypto_wallet",
      "id": "b6705e3a-3c6c-49b0-b24f-d55aafd03635",
      "crypto_asset": "USDC"
    },
    "destination": {
      "destination_type": "crypto_wallet",
      "wallet_address": "76YbQbwcPcp8MTy6pP8efkicPhTUfYYxeEPuCQmo46K1",
      "blockchain_network": "solana"
    },
    "amount": "1000.00",
    "description": "October contract",
    "client_reference": "pay-ctr-1009"
  }),
});
console.log(response.status, await response.json());
```
```python title="Python"
import os

import requests

response = requests.post(
    "https://api.gravv.xyz/v1/transfer",
    headers={
        "Api-Key": os.environ["GRAVV_API_KEY"],
        "Content-Type": "application/json",
        "Idempotency-Key": "f207b686-1dd1-4bf2-8b4e-6442681aa37f",
    },
    json={
        "customer_id": "c7ae0522-6a4d-476f-a43c-5a9aac863c31",
        "source": {
            "source_type": "internal_crypto_wallet",
            "id": "b6705e3a-3c6c-49b0-b24f-d55aafd03635",
            "crypto_asset": "USDC",
        },
        "destination": {
            "destination_type": "crypto_wallet",
            "wallet_address": "76YbQbwcPcp8MTy6pP8efkicPhTUfYYxeEPuCQmo46K1",
            "blockchain_network": "solana",
        },
        "amount": "1000.00",
        "description": "October contract",
        "client_reference": "pay-ctr-1009",
    },
)
print(response.status_code, response.json())
```
</CodeGroup>

```json title="Response"
{
  "data": {
    "amount": "1000",
    "amount_currency": "USD",
    "date_created": "2026-10-13T15:10:00.000Z",
    "fee": "0",
    "fee_currency": "USD",
    "local_amount": null,
    "local_currency": null,
    "reference": "657b085b-096a-4779-9cbb-6d7f0689cc65",
    "requires_approval": false,
    "transaction_id": "ea2bfda0-e733-4245-befe-2ca64e43cfcc",
    "transfer_status": "pending"
  },
  "error": null
}
```

To send to another Gravv wallet instead, which can belong to any of your customers, send `"destination": {"destination_type": "internal_crypto_wallet", "id": "<wallet id>"}`. For an outside Stellar address, you can add `blockchain_memo`.

### 2. Wait for it

The move has several on-chain steps, so several `transfer.status.pending` events arrive first. Wait for `transfer.status.completed` (with `tx_hash`), or poll [`GET /v1/transactions/ea2bfda0-e733-4245-befe-2ca64e43cfcc`](/api-reference/transactions/get-v1-transactions-transaction-id). A cross-network transfer can stay `pending` for a long time. If it does, contact support with the `reference` instead of sending again.

## What can go wrong

| Response | Why | Fix |
| :-- | :-- | :-- |
| 400 `transfers between different blockchain networks support USDC only, on avalanche, ethereum, polygon, solana and stellar` | A network is outside the list (such as base or tron), or one side uses USDT | Use USDC on a listed network. Convert USDT first |
| 400 `destination.wallet_address is not a valid solana address` (or ethereum, stellar, …) | The address does not match the network, or it is a muxed Stellar `M…` address | Get the right address for that network |
| 400 `transfers from avalanche accounts are not currently supported` | Avalanche can receive but not send | Send from another network |
| 400 `the source account (…) and destination (…) must be on the same blockchain network` | The source is an account rather than a wallet, so it cannot move across networks | Use an `internal_crypto_wallet` source |
| 400 `insufficient balance` | The amount plus the fee is more than the balance | Fund the wallet |
| The receiver got the amount rounded to 2 decimal places | You sent more than 2 decimal places | Send at most 2 decimal places |
| `transfer.status.failed`, but the transaction is still `pending` | For example, the Stellar receiver has no USDC trustline. The last step cannot complete, so a person handles it | Do not send it again. Contact support with the `reference`, and ask the receiver to enable USDC |

## Webhooks you will receive

1. `transfer.status.pending`, several times, with `workflow_type` `cross_chain_self_transfer`.
2. `transfer.status.completed` with `tx_hash`, or `transfer.status.failed`.

## Testing in sandbox

In sandbox, the request checks for USDT, an unlisted network and a malformed address behave as described. The move itself does not complete in sandbox:

- A send to an outside Solana address goes to manual review within seconds. Gravv sends `transfer.status.failed` with `transfer_status` `manual_processing_required`, and the transaction stays `pending`.
- A send to the customer's own Stellar wallet stays `pending`.

Do not use sandbox to fund a wallet on another network.

## Reference

- [Create a transfer](/api-reference/transfer/post-v1-transfer)
- [Crypto transfers](/platform/transfers/crypto-transfers)
