This guide walks you through the basics of accepting USDC on your site or in
your app with Managed Payments stablecoin payins. You create payment intents,
show a deposit address, your customer sends USDC, and Circle links the onchain
payment to your intent. The steps use a continuous payment intent, which is the
default pattern and fits a stable receive address per merchant or sub-wallet.
The alternative Quickstart: Crypto
Deposits walkthrough covers a
transient payment intent instead (amount and time window set on create). Use
that guide when you want a one-time, expiring checkout-style intent.
Prerequisites
Before you start, ensure you have:
- Aligned with Circle on your Managed Payments onboarding model (Direct or
Intermediary).
- Completed Managed Payments onboarding, depending on your preferred model, with
Circle and have API credentials for the environment you target. The cURL
examples use the sandbox host
api-sandbox.circle.com.
- Roles that allow creating and reading payment intents and payments in your
setup. Circle assigns roles during onboarding.
- Sub-wallets or any other structure your setup requires so each continuous
intent ties to the right merchant or segment. See
Managed Payments and the
Stablecoin Accounts API
if you create accounts first.
- (Optional) A webhook receiver or queue to handle payment intent and payment
events. Follow the
notifications quickstart.
- (Optional) For an end-to-end test, a payer wallet with USDC and native gas on
the chain you set on the intent (for example Sepolia ETH when the intent uses
an Ethereum test chain).
Sequence diagram
Continuous payins use settlement currency and chain on create; you may see
active instead of pending when the address is ready.
Steps
- Set up payment intent to pay with stablecoin
- Acquire blockchain address customer will pay to
- Customer pays
- Receive payment
1. Pay with stablecoin
Once the customer reaches checkout and confirms they would like to pay with USDC
on Ethereum, your system sends Circle a request to
create a payment intent.
In this continuous payment intent you specify the settlement currency and
chain (no fixed charge amount on create).
Create a payment intent:
curl --location --request POST 'https://api-sandbox.circle.com/v1/paymentIntents' \
--header 'X-Requested-Id: ${GUID}' \
--header 'Authorization: Bearer ${YOUR_API_KEY}' \
--header 'Content-Type: application/json' \
--data-raw '{
"idempotencyKey": "17607606-e383-4874-87c3-7e46a5dc03dd",
"settlementCurrency": "USD",
"paymentMethods": [
{
"type": "blockchain",
"chain": "ETH"
}
]
}'
{
"data": {
"type": "continuous",
"id": "e7b49cb6-1f78-4a0f-8fd6-35fc74dca335",
"amountPaid": {
"amount": "0.00",
"currency": "USD"
},
"amountRefunded": {
"amount": "0.00",
"currency": "USD"
},
"settlementCurrency": "USD",
"paymentMethods": [
{
"type": "blockchain",
"chain": "ETH"
}
],
"timeline": [
{
"status": "created",
"time": "2026-03-23T17:41:19.986668Z"
}
],
"createDate": "2026-03-23T17:41:19.979669Z",
"updateDate": "2026-03-23T17:41:19.979669Z",
"merchantWalletId": "1000700366",
"currency": "USD"
}
}
{
"clientId": "5b057f1e-743c-4aeb-beeb-ef7b2e16f291",
"notificationType": "paymentIntents",
"version": 1,
"customAttributes": {
"clientId": "5b057f1e-743c-4aeb-beeb-ef7b2e16f291"
},
"paymentIntent": {
"type": "continuous",
"id": "e7b49cb6-1f78-4a0f-8fd6-35fc74dca335",
"amountPaid": {
"amount": "0.00",
"currency": "USD"
},
"amountRefunded": {
"amount": "0.00",
"currency": "USD"
},
"settlementCurrency": "USD",
"paymentMethods": [
{
"type": "blockchain",
"chain": "ETH"
}
],
"timeline": [
{
"status": "created",
"time": "2026-03-23T17:41:19.986668Z"
}
],
"createDate": "2026-03-23T17:41:19.979669Z",
"updateDate": "2026-03-23T17:41:19.979669Z",
"merchantWalletId": "12345",
"currency": "USD"
}
}
2. Acquire blockchain address customer will pay to
For security reasons, the API does not return the deposit blockchain address in
the create response. To retrieve the blockchain deposit address, you have two
options:
- Subscribe to webhook notifications
- Poll Circle APIs
Option 1: Webhook notification
To receive webhook notifications, follow the steps in the
notifications quickstart.
After you subscribe to notifications, you receive updates for the payment intent
whenever the resource is updated. In this case, when the
paymentMethods.address is set, a notification is sent with a new timeline
object with a status of active.
Payment intent webhook notification
{
"clientId": "5b057f1e-743c-4aeb-beeb-ef7b2e16f291",
"notificationType": "paymentIntents",
"version": 1,
"customAttributes": {
"clientId": "5b057f1e-743c-4aeb-beeb-ef7b2e16f291"
},
"paymentIntent": {
"type": "continuous",
"id": "e7b49cb6-1f78-4a0f-8fd6-35fc74dca335",
"amountPaid": {
"amount": "0.00",
"currency": "USD"
},
"amountRefunded": {
"amount": "0.00",
"currency": "USD"
},
"settlementCurrency": "USD",
"paymentMethods": [
{
"type": "blockchain",
"chain": "ETH",
"address": "0xfd5a9f666d96022d13a73e3638fb7ec958696fbe"
}
],
"fees": [
{
"type": "blockchainLeaseFee",
"amount": "0.00",
"currency": "USD"
}
],
"timeline": [
{
"status": "active",
"time": "2026-03-23T17:41:23.450386Z"
},
{
"status": "created",
"time": "2026-03-23T17:41:19.986668Z"
}
],
"createDate": "2026-03-23T17:41:19.979669Z",
"updateDate": "2026-03-23T17:41:23.405690Z",
"merchantWalletId": "12345",
"currency": "USD"
}
}
Option 2: Poll payment intent endpoint
If you prefer to poll
get a payment intent,
send GET requests until you receive paymentMethods.address.
Retrieve payment intent:
curl --location --request GET 'https://api-sandbox.circle.com/v1/paymentIntents/{id}' \
--header 'X-Requested-Id: ${GUID}' \
--header 'Authorization: Bearer ${YOUR_API_KEY}'
{
"data": {
"type": "continuous",
"id": "e7b49cb6-1f78-4a0f-8fd6-35fc74dca335",
"amountPaid": {
"amount": "0.00",
"currency": "USD"
},
"amountRefunded": {
"amount": "0.00",
"currency": "USD"
},
"settlementCurrency": "USD",
"paymentMethods": [
{
"type": "blockchain",
"chain": "ETH",
"address": "0xfd5a9f666d96022d13a73e3638fb7ec958696fbe"
}
],
"fees": [
{
"type": "blockchainLeaseFee",
"amount": "0.00",
"currency": "USD"
}
],
"timeline": [
{
"status": "active",
"time": "2026-03-23T17:41:23.450386Z"
},
{
"status": "created",
"time": "2026-03-23T17:41:19.986668Z"
}
],
"createDate": "2026-03-23T17:41:19.979669Z",
"updateDate": "2026-03-23T17:41:23.405690Z",
"merchantWalletId": "12345",
"currency": "USD"
}
}
3. Enable customer payment
Once you receive the deposit address via paymentMethods.address, share it with
the customer so they can send funds on the correct chain.
A continuous payment intent doesn’t define a fixed amount on create; you
communicate any specific charge (for example an invoice total) from your own
checkout or UI.
You can present the address two ways:
- as plain text the customer can cut and paste; or
- as a QR code the customer can scan via an app.
The customer then sends payment from their wallet (custodial or non-custodial).
When using transient payment intents, you can set a time frame in which the
customer must send payment by adjusting the expiresOn setting.
4. Receive payment from Circle
Once Circle obtains payment onchain, Circle creates a Payment resource linked to
the Payment Intent created earlier and updates the status of that Payment
Intent. Your firm will then receive payment via the method specified.
Option 1: Webhook notifications
Payment intent webhook notification
{
"clientId": "5b057f1e-743c-4aeb-beeb-ef7b2e16f291",
"notificationType": "paymentIntents",
"version": 1,
"customAttributes": {
"clientId": "5b057f1e-743c-4aeb-beeb-ef7b2e16f291"
},
"paymentIntent": {
"type": "continuous",
"id": "e7b49cb6-1f78-4a0f-8fd6-35fc74dca335",
"amountPaid": {
"amount": "5.00",
"currency": "USD"
},
"amountRefunded": {
"amount": "0.00",
"currency": "USD"
},
"settlementCurrency": "USD",
"paymentMethods": [
{
"type": "blockchain",
"chain": "ETH",
"address": "0xfd5a9f666d96022d13a73e3638fb7ec958696fbe"
}
],
"fees": [
{
"type": "blockchainLeaseFee",
"amount": "0.00",
"currency": "USD"
},
{
"type": "totalPaymentFees",
"amount": "0.00",
"currency": "USD"
}
],
"timeline": [
{
"status": "active",
"time": "2026-03-23T17:41:23.450386Z"
},
{
"status": "created",
"time": "2026-03-23T17:41:19.986668Z"
}
],
"createDate": "2026-03-23T17:41:19.979669Z",
"updateDate": "2026-03-23T17:52:18.080633Z",
"merchantWalletId": "12345",
"currency": "USD"
}
}
Payment webhook notification
{
"clientId": "5b057f1e-743c-4aeb-beeb-ef7b2e16f291",
"notificationType": "payments",
"version": 1,
"customAttributes": {
"clientId": "5b057f1e-743c-4aeb-beeb-ef7b2e16f291"
},
"payment": {
"id": "021ff661-e7d5-332f-bb9c-e43870608f26",
"type": "payment",
"status": "pending",
"amount": {
"amount": "5.00",
"currency": "USD"
},
"createDate": "2026-03-23T17:49:54.197Z",
"updateDate": "2026-03-23T17:49:54.259Z",
"merchantId": "5b057f1e-743c-4aeb-beeb-ef7b2e16f291",
"merchantWalletId": "12345",
"paymentIntentId": "e7b49cb6-1f78-4a0f-8fd6-35fc74dca335",
"fromAddresses": {
"chain": "ETH",
"addresses": ["0x6dbe810e3314546009bd6e1b29f9031211cda5d2"]
},
"depositAddress": {
"chain": "ETH",
"address": "0xfd5a9f666d96022d13a73e3638fb7ec958696fbe"
},
"transactionHash": "0xfbc0f1c8256af3453fd3be7a1491e3581e072022a29ffc78cf129a662182305e"
}
}
Option 2: Retrieve payment intent and payment
Retrieve a payment intent:
curl --location --request GET 'https://api-sandbox.circle.com/v1/paymentIntents/{id}' \
--header 'X-Requested-Id: ${GUID}' \
--header 'Authorization: Bearer ${YOUR_API_KEY}'
{
"data": {
"type": "continuous",
"id": "e7b49cb6-1f78-4a0f-8fd6-35fc74dca335",
"amountPaid": {
"amount": "5.00",
"currency": "USD"
},
"amountRefunded": {
"amount": "0.00",
"currency": "USD"
},
"settlementCurrency": "USD",
"paymentMethods": [
{
"type": "blockchain",
"chain": "ETH",
"address": "0xfd5a9f666d96022d13a73e3638fb7ec958696fbe"
}
],
"fees": [
{
"type": "blockchainLeaseFee",
"amount": "0.00",
"currency": "USD"
},
{
"type": "totalPaymentFees",
"amount": "0.00",
"currency": "USD"
}
],
"timeline": [
{
"status": "active",
"time": "2026-03-23T17:41:23.450386Z"
},
{
"status": "created",
"time": "2026-03-23T17:41:19.986668Z"
}
],
"createDate": "2026-03-23T17:41:19.979669Z",
"updateDate": "2026-03-23T17:52:18.080633Z",
"merchantWalletId": "12345",
"currency": "USD"
}
}
Retrieve a payment:
curl --location --request GET 'https://api-sandbox.circle.com/v1/payments/{id}' \
--header 'X-Requested-Id: ${GUID}' \
--header 'Authorization: Bearer ${YOUR_API_KEY}'
{
"data": {
"id": "021ff661-e7d5-332f-bb9c-e43870608f26",
"type": "payment",
"status": "paid",
"amount": {
"amount": "5.00",
"currency": "USD"
},
"fees": {
"amount": "0.00",
"currency": "USD"
},
"createDate": "2026-03-23T17:49:54.197184Z",
"updateDate": "2026-03-23T17:52:17.910610Z",
"merchantId": "5b057f1e-743c-4aeb-beeb-ef7b2e16f291",
"merchantWalletId": "12345",
"paymentIntentId": "e7b49cb6-1f78-4a0f-8fd6-35fc74dca335",
"settlementAmount": {
"amount": "5.00",
"currency": "USD"
},
"fromAddresses": {
"chain": "ETH",
"addresses": ["0x6dbe810e3314546009bd6e1b29f9031211cda5d2"]
},
"depositAddress": {
"chain": "ETH",
"address": "0xfd5a9f666d96022d13a73e3638fb7ec958696fbe"
},
"transactionHash": "0xfbc0f1c8256af3453fd3be7a1491e3581e072022a29ffc78cf129a662182305e"
}
}
For blockchains that require a ‘memo’ or ‘address tag’ (XLM, HBAR, etc.), the
optional addressTag field will be present in the depositAddress object.