Skip to main content

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.

Use the Stablecoin Payins API to accept an onchain USDC or EURC payment into your Circle Mint account. You create a payment intent, share the deposit address that Circle assigns, and then confirm the payment after the customer transfers funds. For background on how payment intents and payments relate to one another, see Stablecoin payins and payouts.

Prerequisites

Before you begin:
  • Stablecoin Payins is enabled on your Circle Mint account. Activation is scoped to the Americas (Circle LLC)—contact your Circle representative or reach out through the Circle Mint contact form to request access.
  • You have a Circle Mint sandbox API key. See Getting started for setup.
  • You have selected a blockchain that the Stablecoin Payins API supports. The Payins API supports a narrower set of blockchains than the Payouts API. See Supported chains and currencies to confirm coverage.
  • You have a merchantWalletId for the wallet that receives settled funds. You do not need a funded Mint account—this is a receive flow.

Steps

1

Create a payment intent

Send a POST request to /v1/paymentIntents to create a payment intent. Use continuous mode, the default, unless you need a fixed-amount, single-checkout intent.
curl -X POST https://api-sandbox.circle.com/v1/paymentIntents \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "idempotencyKey": "17607606-e383-4874-87c3-7e46a5dc03dd",
    "currency": "USD",
    "settlementCurrency": "USD",
    "merchantWalletId": "1000999922",
    "paymentMethods": [
      {
        "type": "blockchain",
        "chain": "BASE"
      }
    ]
  }'
The response includes the intent id and a timeline showing the created status. The deposit address is not yet populated.
{
  "data": {
    "id": "e2e90ba3-9d1f-490d-9460-24ac6eb55a1b",
    "currency": "USD",
    "settlementCurrency": "USD",
    "amountPaid": { "amount": "0.00", "currency": "USD" },
    "paymentMethods": [
      {
        "type": "blockchain",
        "chain": "BASE"
      }
    ],
    "timeline": [
      {
        "status": "created",
        "time": "2026-04-12T20:13:35.579331Z"
      }
    ],
    "type": "continuous",
    "createDate": "2026-04-12T20:13:35.578678Z",
    "updateDate": "2026-04-12T20:13:35.578678Z"
  }
}
To create a fixed-amount, single-use intent, set type to transient and include an amount. The deposit address that Circle assigns is single-use and the intent expires after expiresOn. Send the same POST /v1/paymentIntents request with this body instead:
{
  "idempotencyKey": "17607606-e383-4874-87c3-7e46a5dc03dd",
  "type": "transient",
  "amount": {
    "amount": "1.00",
    "currency": "USD"
  },
  "settlementCurrency": "USD",
  "merchantWalletId": "1000999922",
  "paymentMethods": [
    {
      "type": "blockchain",
      "chain": "BASE"
    }
  ]
}
2

Get the deposit address

Circle assigns the deposit address asynchronously after the intent is created. Use webhooks or polling to retrieve it.
Subscribe to paymentIntents notifications. When Circle assigns the address, you receive a payload whose paymentMethods[0].address is populated and whose timeline advances to pending.
{
  "notificationType": "paymentIntents",
  "version": 1,
  "paymentIntent": {
    "id": "e2e90ba3-9d1f-490d-9460-24ac6eb55a1b",
    "paymentMethods": [
      {
        "type": "blockchain",
        "chain": "BASE",
        "address": "0x97de855690955e0da79ce5c1b6804847e7070c7f"
      }
    ],
    "timeline": [
      { "status": "pending", "time": "2026-04-12T20:13:38.188286Z" },
      { "status": "created", "time": "2026-04-12T20:13:35.579331Z" }
    ]
  }
}
For memo-based blockchains such as Stellar (XLM) and Hedera (HBAR), the payment method also includes an addressTag. If your customer’s wallet enforces memos, they must include this tag when sending funds.
3

Customer transfers funds

Display the deposit address (and addressTag if applicable) to your customer. The customer sends USDC or EURC to that address from their wallet. This step takes place outside the API.
The deposit address is valid only on the blockchain assigned to the payment intent. Funds sent on any other blockchain are not credited and are permanently lost.
4

Confirm the payment

After the onchain transfer settles, Circle creates a payment object linked to the intent. The intent’s own state machine differs by mode:
  • Continuous intents stay at active. The intent timeline does not advance to complete, and the intent’s paymentIds array is not populated. Reconcile each settled transfer through the payments webhook or by listing payments with GET /v1/payments?paymentIntentId={id}.
  • Transient intents transition to complete after the single expected transfer settles. The latest timeline entry carries a context of paid, underpaid, or overpaid, and the intent’s paymentIds array lists the settled payments.
A payments notification fires whenever an inbound transfer settles. The payload includes the payment status, the originating fromAddresses, the onchain transactionHash, and the paymentIntentId that links the payment back to its intent. This works the same for continuous and transient intents.
{
  "notificationType": "payments",
  "version": 1,
  "payment": {
    "id": "66c56b6a-fc79-338b-8b94-aacc4f0f18de",
    "type": "payment",
    "status": "paid",
    "amount": { "amount": "1.00", "currency": "USD" },
    "paymentIntentId": "e2e90ba3-9d1f-490d-9460-24ac6eb55a1b",
    "fromAddresses": {
      "chain": "BASE",
      "addresses": ["0x0d4344cff68f72a5b9abded37ca5862941a62050"]
    },
    "depositAddress": {
      "chain": "BASE",
      "address": "0x97de855690955e0da79ce5c1b6804847e7070c7f"
    },
    "transactionHash": "0x7351585460bd657f320b9afa02a52c26d89272d0d10cc29913eb8b28e64fd906"
  }
}
For transient intents only, a paymentIntents notification also fires when the intent reaches complete, with a new timeline entry whose status is complete and whose context describes the outcome (paid, underpaid, or overpaid). Continuous intents do not produce this notification.
5

(Optional) Expire a transient intent

If a customer abandons checkout, you can expire a transient payment intent manually by calling POST /v1/paymentIntents/{id}/expire. This action applies only to transient intents.
curl -X POST https://api-sandbox.circle.com/v1/paymentIntents/6e4d4047-db14-4c09-b238-1215aee50d03/expire \
  -H "Authorization: Bearer $API_KEY"
Funds sent to the deposit address after the intent expires are still credited to your Circle Mint account, but they do not match the original intent. You may need to contact Circle Support to reconcile these transfers.

Handle completion contexts (transient intents)

Completion contexts apply only to transient intents, because they have a target amount to compare against. Continuous intents stay at active and never reach complete, so no context is produced. When a transient intent reaches complete, the context on the latest timeline entry tells you how the amount paid compares to what was expected. Each context calls for a different downstream action.
ContextMeaningTypical handling
paidThe customer paid the expected amount. For transient intents, amountPaid equals amount.Fulfill the order.
underpaidThe customer paid less than the expected amount on a transient intent.Refund the partial payment or contact the customer to top up. See Refund a stablecoin payin.
overpaidThe customer paid more than expected.Refund the excess to the sender, or refund the full amount and ask the customer to retry.

See also