Skip to main content
This quickstart walks through how to accept an onchain USDC or EURC stablecoin payin with Circle Mint by creating a payment intent, obtaining a deposit address, and confirming the transfer. The examples use Ethereum, but you can use any supported blockchain.

Prerequisites

Before you begin, ensure that you’ve:
  • Obtained a Circle Mint sandbox API key with access to the Stablecoin Payins
  • Obtained a Circle Mint sandbox API key with access to the Crypto Deposits API.
  • Obtained a merchantWalletId for the wallet that receives settled funds.
  • Installed cURL for API calls.
  • (Optional) Configured webhook notifications.

Step 1: Create a payment intent

When the customer chooses to pay with USDC or EURC onchain, call Create a payment intent and choose a continuous or transient payment intent mode.
Continuous payment intents are the default type. You do not include an amount at creation.Example request to create a continuous payment intent:
cURL
curl --location --request POST 'https://api-sandbox.circle.com/v1/paymentIntents' \
--header 'X-Request-Id: ${GUID}' \
--header 'Authorization: Bearer ${YOUR_API_KEY}' \
--header 'Content-Type: application/json' \
--data-raw '{
  "idempotencyKey": "17607606-e383-4874-87c3-7e46a5dc03dd",
  "currency": "USD",
  "settlementCurrency": "USD",
  "merchantWalletId": "${MERCHANT_WALLET_ID}",
  "paymentMethods": [
    {
      "type": "blockchain",
      "chain": "ETH"
    }
  ],
  "type": "continuous"
}'
Example response:
JSON
{
  "data": {
    "id": "e2e90ba3-9d1f-490d-9460-24ac6eb55a1b",
    "currency": "USD",
    "settlementCurrency": "USD",
    "amountPaid": {
      "amount": "0.00",
      "currency": "USD"
    },
    "paymentMethods": [
      {
        "type": "blockchain",
        "chain": "ETH"
      }
    ],
    "timeline": [
      {
        "status": "created",
        "time": "2023-01-21T20:13:35.579331Z"
      }
    ],
    "type": "continuous",
    "createDate": "2023-01-21T20:13:35.578678Z",
    "updateDate": "2023-01-21T20:13:35.578678Z"
  }
}

Step 2: Obtain the deposit address

Circle does not return the deposit address in the initial response to creating a payment intent. Use webhook notifications or continuous polling to get the deposit address.
After you subscribe to notifications for paymentIntents, you receive updates when the payment intent changes. When paymentMethods.address is set, the payload includes an updated timeline of the historical payment intent statuses and timestamps.Example paymentIntents notification after the deposit address is assigned:
{
  "clientId": "f1397191-56e6-42fd-be86-0a7b9bd91522",
  "notificationType": "paymentIntents",
  "version": 1,
  "customAttributes": { "clientId": "f1397191-56e6-42fd-be86-0a7b9bd91522" },
  "paymentIntent": {
    "id": "e2e90ba3-9d1f-490d-9460-24ac6eb55a1b",
    "currency": "USD",
    "settlementCurrency": "USD",
    "amountPaid": { "amount": "0.00", "currency": "USD" },
    "amountRefunded": { "amount": "0.00", "currency": "USD" },
    "paymentMethods": [
      {
        "type": "blockchain",
        "chain": "ETH",
        "address": "0x97de855690955e0da79ce5c1b6804847e7070c7f"
      }
    ],
    "fees": [
      { "type": "blockchainLeaseFee", "amount": "0.00", "currency": "USD" }
    ],
    "paymentIds": [],
    "refundIds": [],
    "timeline": [
      { "status": "pending", "time": "2023-01-21T20:13:38.188286Z" },
      { "status": "created", "time": "2023-01-21T20:13:35.579331Z" }
    ],
    "type": "continuous",
    "createDate": "2023-01-21T20:13:35.578678Z",
    "updateDate": "2023-01-21T20:13:38.186831Z"
  }
}

Step 3: Customer makes payment

Once you’ve obtained the deposit address, display it to the customer and instruct them to send the payment.

3.1. Display the deposit address

Pass the deposit address to the customer along with the stablecoin asset to send (USDC or EURC), and (for transient intents) the amount to pay. You can display the address in plain text or as a QR code to scan from a wallet.
For transient payment intents, you can display the expiresOn time to show the customer how long they have to pay.If the customer does not send funds before expiresOn, the payment intent moves to a complete status with context expired. You cannot reuse an expired intent. Create a new payment intent to retry the checkout.

3.2. Customer sends funds onchain

The customer makes the payment by sending USDC or EURC to the deposit address on the specified blockchain.

Step 4: Confirm payment completion

After Circle confirms the onchain transfer, it updates the payment intent and creates a payment for that same inbound transfer. The intent tracks whether the checkout is paid, while the payment records the onchain transaction hash and sender address. Treat the payin as complete when both records match what you expect. Use webhook notifications or continuous polling to inspect the intent and payment.

Step 4.1. Inspect the payment intent

Subscribe to paymentIntents notifications. After the customer pays, the payload includes an updated timeline, amountPaid, and paymentIds.Example when the payment intent is complete and paid:
{
  "clientId": "f1397191-56e6-42fd-be86-0a7b9bd91522",
  "notificationType": "paymentIntents",
  "version": 1,
  "customAttributes": { "clientId": "f1397191-56e6-42fd-be86-0a7b9bd91522" },
  "paymentIntent": {
    "id": "e2e90ba3-9d1f-490d-9460-24ac6eb55a1b",
    "currency": "USD",
    "settlementCurrency": "USD",
    "amountPaid": { "amount": "1.00", "currency": "USD" },
    "amountRefunded": { "amount": "0.00", "currency": "USD" },
    "paymentMethods": [
      {
        "type": "blockchain",
        "chain": "ETH",
        "address": "0x97de855690955e0da79ce5c1b6804847e7070c7f"
      }
    ],
    "fees": [
      { "type": "blockchainLeaseFee", "amount": "0.00", "currency": "USD" },
      { "type": "totalPaymentFees", "amount": "0.01", "currency": "USD" }
    ],
    "paymentIds": ["66c56b6a-fc79-338b-8b94-aacc4f0f18de"],
    "refundIds": [],
    "timeline": [
      {
        "status": "complete",
        "context": "paid",
        "time": "2023-01-21T20:19:24.861094Z"
      },
      { "status": "pending", "time": "2023-01-21T20:13:38.188286Z" },
      { "status": "created", "time": "2023-01-21T20:13:35.579331Z" }
    ],
    "type": "continuous",
    "createDate": "2023-01-21T20:13:35.578678Z",
    "updateDate": "2023-01-21T20:19:24.859052Z"
  }
}

Step 4.2. Inspect the payment for the same transfer

A payment is linked to the payment intent and carries the onchain transaction hash and the customer’s sending address for that specific transfer.
Subscribe to payments notifications to receive the updated payment object when the transfer settles.
JSON
{
  "clientId": "f1397191-56e6-42fd-be86-0a7b9bd91522",
  "notificationType": "payments",
  "version": 1,
  "customAttributes": { "clientId": "f1397191-56e6-42fd-be86-0a7b9bd91522" },
  "payment": {
    "id": "66c56b6a-fc79-338b-8b94-aacc4f0f18de",
    "type": "payment",
    "status": "paid",
    "amount": { "amount": "1.00", "currency": "USD" },
    "fees": { "amount": "0.01", "currency": "USD" },
    "createDate": "2023-01-21T20:16:35.092Z",
    "updateDate": "2023-01-21T20:19:24.719Z",
    "merchantId": "f1397191-56e6-42fd-be86-0a7b9bd91522",
    "merchantWalletId": "1000999922",
    "paymentIntentId": "e2e90ba3-9d1f-490d-9460-24ac6eb55a1b",
    "settlementAmount": { "amount": "1.00", "currency": "USD" },
    "fromAddresses": {
      "chain": "ETH",
      "addresses": ["0x0d4344cff68f72a5b9abded37ca5862941a62050"]
    },
    "depositAddress": {
      "chain": "ETH",
      "address": "0x97de855690955e0da79ce5c1b6804847e7070c7f"
    },
    "transactionHash": "0x7351585460bd657f320b9afa02a52c26d89272d0d10cc29913eb8b28e64fd906"
  }
}
For blockchains that use a memo or address tag (for example, XLM or HBAR), the addressTag field can appear on depositAddress in payment payloads.
The payment is complete when status is paid.