Swap
A swap converts stablecoins between chains or token types (e.g. USDC on Base to USDT on Polygon) using Celar's bridging infrastructure. Swaps run on mainnet only.
Swaps are available on mainnet only. Sandbox does not support this operation type. Use
base,polygon, orarbitrumas chain values.
How it works
With a Celar wallet (walletId provided)
- Submit a
swaprequest withsource.walletId— Celar holds the source wallet - Celar quotes the cross-chain route via Relay and returns a quote +
payment_id - Call
POST /payments/swap/finalizeto execute the swap - Celar submits the swap transactions through the customer's smart account
- Tokens arrive on the destination chain
- Monitor via
transfer.confirmedandtransfer.settledwebhooks
Without a wallet (walletId omitted)
- Submit a
swaprequest withoutsource.walletId - Celar returns an
intermediary_walletaddress and amagic_link_url - Send the exact amount of source tokens to the intermediary wallet
- Celar detects the deposit and executes the swap automatically
- Tokens arrive on the destination chain
Prerequisites
- A valid
customer_id: see Register a Customer - If using a Celar wallet: a funded wallet (
walletId) holding the source token - A unique
Idempotency-Keyfor the request
Initiate a Swap
Submit the swap request to POST /payments/transfer with operationType: "swap".
- With walletId
- Without walletId
curl --request POST \
--url https://api.celar.io/api/v1/payments/transfer \
--header 'Authorization: Bearer <your_api_key>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <unique_uuid>' \
--data '{
"operationType": "swap",
"customer_id": "cr_2ae76bc76f03437d",
"amount": 100,
"source": {
"currency": "USDC",
"chain": "base",
"walletId": "cw_1053b738d73ad9b5"
},
"destination": {
"currency": "USDT",
"chain": "polygon",
"address": "0xabc123def456abc123def456abc123def456abc1"
}
}'
Response:
{
"payment_id": "swap_9b858103f825a5b4",
"quote": {
"id": "rq_abc123",
"amount": "99.50",
"fees": "0.50"
},
"status": "pending"
}
| Field | Required | Description |
|---|---|---|
payment_id | Unique swap payment identifier | |
quote.id | Relay quote identifier for the swap route | |
quote.amount | Estimated output amount on the destination chain (formatted) | |
quote.fees | Estimated relayer fees for the swap (formatted) | |
status | pending |
Then finalize the swap to execute it.
curl --request POST \
--url https://api.celar.io/api/v1/payments/transfer \
--header 'Authorization: Bearer <your_api_key>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <unique_uuid>' \
--data '{
"operationType": "swap",
"customer_id": "cr_2ae76bc76f03437d",
"amount": 100,
"source": {
"currency": "USDC",
"chain": "base"
},
"destination": {
"currency": "USDT",
"chain": "polygon"
}
}'
Response:
{
"payment_id": "swap_9b858103f825a5b4",
"status": "pending",
"magic_link_url": "https://pay.celar.io/swap_9b858103f825a5b4",
"chain": "base",
"intermediary_wallet": "0xdF8CA3Ef74b989F2dC781bFdfCdD2758556C5223",
"amount": 100,
"currency": "USDC"
}
| Field | Required | Description |
|---|---|---|
payment_id | Unique swap payment identifier | |
status | pending | |
magic_link_url | Hosted checkout URL showing the intermediary wallet to fund | |
chain | Blockchain network the intermediary wallet is on | |
intermediary_wallet | Wallet address to send the source tokens to | |
amount | Amount to send to the intermediary wallet | |
currency | Token to send to the intermediary wallet |
info
The swap executes automatically once funds arrive at the intermediary wallet. No finalize step needed.
Finalize
Execute a quoted swap. Only valid for swaps initiated with a walletId.
curl --request POST \
--url https://api.celar.io/api/v1/payments/swap/finalize \
--header 'Authorization: Bearer <your_api_key>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <unique_uuid>' \
--data '{
"paymentId": "swap_9b858103f825a5b4"
}'
Response:
{
"message": "Swap finalized",
"hash": "0x4c5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f"
}
| Field | Required | Description |
|---|---|---|
message | Confirmation that the swap was finalized | |
hash | On-chain transaction hash of the submitted swap |
Finalize request fields
| Field | Required | Description |
|---|---|---|
paymentId | Yes | ID of the swap payment to finalize |
Field reference (initiate)
| Field | Required | Description |
|---|---|---|
operationType | Yes | swap |
customer_id | Yes | The customer whose wallet is being used |
amount | Yes | Amount of the source token to swap |
source.currency | Yes | USDC or USDT |
source.chain | Yes | base, polygon, arbitrum, or |
source.walletId | No | Celar wallet ID holding the source token. If omitted, Celar returns an intermediary wallet for you to fund. |
destination.currency | Yes | USDC or USDT |
destination.chain | Yes | base, polygon, arbitrum, or |
destination.address | No | External address to deliver swapped tokens to. If omitted, tokens go to the customer’s Celar wallet on the destination chain. |
Supported swap routes
Any combination of the following is supported:
| Field | Required | Description |
|---|---|---|
USDC | base, polygon, arbitrum, | |
USDT | base, polygon, arbitrum, |
Webhook events
Swaps emit the same transfer events as other operations:
| Event | When it fires |
|---|---|
transfer.confirmed | Swap deposit detected on-chain |
transfer.settled | Swap completed — tokens delivered to destination |
transfer.failed | Swap execution failed |
See Webhooks for the full reference.
Notes
- Swaps are not available on
baseSepoliaor any testnet environment - Same-chain, same-token swaps (e.g. USDC Base to USDC Base) are not valid
- Settlement time depends on bridge and chain congestion: monitor via webhooks