> ## 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.

# How-to: Refund a stablecoin payin

> Issue a full or partial refund against a settled Stablecoin Payins payment intent using the Circle Mint refund APIs.

Use the Stablecoin Payins API to return funds against a payment intent that has
already received at least one settled payment. You can issue a single full
refund, a single partial refund, or multiple partial refunds up to the settled
total. For the mental model that underpins this procedure, see
[Stablecoin payins and payouts](/circle-mint/concepts/stablecoin-payins-and-payouts).

<Warning>
  Refunds are subject to four hard constraints:

  * You have 30 days from the payment intent's creation date to start a refund.
  * At least one payment on the intent must be settled. You cannot start a refund
    while a payment is still pending.
  * Once a refund starts, the payment intent transitions to `refunded` and stops
    accepting new payins. Treat the intent as terminal and create a new intent for
    any future checkout.
  * Refunds initiated from the Circle Mint console cannot be canceled after
    submission.
</Warning>

Regional availability also affects which payment intents are refundable today.

<Note>
  Refunds for Stablecoin Payins booked through Circle Singapore (CIRCLE\_SG) are
  not supported. See [Travel Rule
  compliance](/circle-mint/references/travel-rule-compliance) for the data model
  that applies to Singapore stablecoin transactions.
</Note>

## Prerequisites

Before you begin:

* A settled payment exists on the payment intent you want to refund. If you have
  not accepted a payin yet, see
  [Receive a stablecoin payin](/circle-mint/howtos/receive-stablecoin-payin).
* You have a refund destination address that you control on the same blockchain
  as the original payment. The destination is merchant-supplied; Circle does not
  automatically return funds to the source wallet.
* You have a Circle Mint sandbox API key. See
  [Getting started](/circle-mint/quickstarts/getting-started) for setup.

## Steps

<Steps>
  <Step title="Inspect the intent to confirm a settled payment">
    Before you initiate a refund, retrieve the payment intent and confirm that at
    least one payment in `paymentIds` is settled. Send a `GET` request to
    `/v1/paymentIntents/{id}`.

    ```bash theme={null}
    curl -X GET https://api-sandbox.circle.com/v1/paymentIntents/e2e90ba3-9d1f-490d-9460-24ac6eb55a1b \
      -H "Authorization: Bearer $API_KEY"
    ```

    A refund-eligible response includes a populated `paymentIds` array, a non-zero
    `amountPaid`, and a `timeline` whose latest entry has `status` `complete` with
    `context` `paid`.

    ```json theme={null}
    {
      "data": {
        "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": "BASE",
            "address": "0x97de855690955e0da79ce5c1b6804847e7070c7f"
          }
        ],
        "paymentIds": ["66c56b6a-fc79-338b-8b94-aacc4f0f18de"],
        "refundIds": [],
        "timeline": [
          {
            "status": "complete",
            "context": "paid",
            "time": "2026-04-12T20:19:24.861094Z"
          },
          { "status": "pending", "time": "2026-04-12T20:13:38.188286Z" },
          { "status": "created", "time": "2026-04-12T20:13:35.579331Z" }
        ],
        "type": "continuous",
        "createDate": "2026-04-12T20:13:35.578678Z",
        "updateDate": "2026-04-12T20:19:24.861094Z"
      }
    }
    ```
  </Step>

  <Step title="Issue the refund">
    Send a `POST` request to `/v1/paymentIntents/{id}/refund`. The body specifies
    the destination you control, the refund amount, and an idempotency key. The
    request uses two amount fields:

    * `amount` carries the source-currency basis; only `currency` is required, and
      the value is derived from `toAmount`.
    * `toAmount` carries the actual refund amount that reaches the destination and
      must include both `amount` and `currency`.

    For memo-based blockchains, add an `addressTag` to the `destination` object.

    <Tabs>
      <Tab title="Partial refund">
        Specify an amount lower than the settled total to return a portion of the
        payment.

        ```bash theme={null}
        curl -X POST https://api-sandbox.circle.com/v1/paymentIntents/e2e90ba3-9d1f-490d-9460-24ac6eb55a1b/refund \
          -H "Authorization: Bearer $API_KEY" \
          -H "Content-Type: application/json" \
          -d @body.json
        ```

        ```json theme={null}
        {
          "idempotencyKey": "9aed1aab-292a-427f-aae1-e0e358fef1c9",
          "destination": {
            "chain": "BASE",
            "address": "0xcd7475eaed9ee9678cf219cec748e25aba068a69"
          },
          "amount": {
            "currency": "USD"
          },
          "toAmount": {
            "amount": "0.50",
            "currency": "USD"
          }
        }
        ```
      </Tab>

      <Tab title="Full refund">
        Specify the full settled amount to return the entire payment.

        ```bash theme={null}
        curl -X POST https://api-sandbox.circle.com/v1/paymentIntents/e2e90ba3-9d1f-490d-9460-24ac6eb55a1b/refund \
          -H "Authorization: Bearer $API_KEY" \
          -H "Content-Type: application/json" \
          -d @body.json
        ```

        ```json theme={null}
        {
          "idempotencyKey": "9aed1aab-292a-427f-aae1-e0e358fef1c9",
          "destination": {
            "chain": "BASE",
            "address": "0xcd7475eaed9ee9678cf219cec748e25aba068a69"
          },
          "amount": {
            "currency": "USD"
          },
          "toAmount": {
            "amount": "1.00",
            "currency": "USD"
          }
        }
        ```
      </Tab>
    </Tabs>

    The response returns a `payment` object with `type` `refund`, `status`
    `pending`, and a `depositAddress` that holds the refund destination Circle will
    use for the onchain transfer.

    ```json theme={null}
    {
      "data": {
        "id": "3389f4ba-aafd-4eef-aaa2-3292df8f62e6",
        "type": "refund",
        "status": "pending",
        "amount": { "currency": "USD" },
        "createDate": "2026-04-13T15:29:58.000000Z",
        "updateDate": "2026-04-13T15:29:58.000000Z",
        "merchantId": "f1397191-56e6-42fd-be86-0a7b9bd91522",
        "merchantWalletId": "1000999922",
        "paymentIntentId": "e2e90ba3-9d1f-490d-9460-24ac6eb55a1b",
        "settlementAmount": { "amount": "0.50", "currency": "USD" },
        "depositAddress": {
          "chain": "BASE",
          "address": "0xcd7475eaed9ee9678cf219cec748e25aba068a69"
        }
      }
    }
    ```

    <Warning>
      The payment intent's `timeline` immediately gains a `refunded` entry and the
      intent becomes terminal. New payins sent to the original deposit address after
      this point may not match the intent and can require Circle Support to
      reconcile.
    </Warning>
  </Step>

  <Step title="Track refund completion">
    Refunds settle asynchronously after the onchain transfer confirms. Use webhooks
    or polling to detect settlement.

    <Tabs>
      <Tab title="Webhook">
        Subscribe to `payments` notifications. The same channel that delivers inbound
        payment events also delivers refund events, discriminated by the `type` field.

        ```json theme={null}
        {
          "notificationType": "payments",
          "version": 1,
          "payment": {
            "id": "3389f4ba-aafd-4eef-aaa2-3292df8f62e6",
            "type": "refund",
            "status": "paid",
            "amount": { "currency": "USD" },
            "paymentIntentId": "e2e90ba3-9d1f-490d-9460-24ac6eb55a1b",
            "settlementAmount": { "amount": "0.50", "currency": "USD" },
            "depositAddress": {
              "chain": "BASE",
              "address": "0xcd7475eaed9ee9678cf219cec748e25aba068a69"
            },
            "transactionHash": "0xa1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456"
          }
        }
        ```
      </Tab>

      <Tab title="Polling">
        Poll `GET /v1/payments/{id}` with the refund `id` from the previous step.

        ```bash theme={null}
        curl -X GET https://api-sandbox.circle.com/v1/payments/3389f4ba-aafd-4eef-aaa2-3292df8f62e6 \
          -H "Authorization: Bearer $API_KEY"
        ```

        The refund is settled when `status` is `paid`. The response also includes the
        onchain `transactionHash`.

        ```json theme={null}
        {
          "data": {
            "id": "3389f4ba-aafd-4eef-aaa2-3292df8f62e6",
            "type": "refund",
            "status": "paid",
            "amount": { "currency": "USD" },
            "fees": { "amount": "0.01", "currency": "USD" },
            "createDate": "2026-04-13T15:29:58.000000Z",
            "updateDate": "2026-04-13T15:35:12.000000Z",
            "merchantId": "f1397191-56e6-42fd-be86-0a7b9bd91522",
            "merchantWalletId": "1000999922",
            "paymentIntentId": "e2e90ba3-9d1f-490d-9460-24ac6eb55a1b",
            "settlementAmount": { "amount": "0.50", "currency": "USD" },
            "depositAddress": {
              "chain": "BASE",
              "address": "0xcd7475eaed9ee9678cf219cec748e25aba068a69"
            },
            "transactionHash": "0xa1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456"
          }
        }
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="(Optional) Issue an additional partial refund">
    If the original refund was partial and the intent still has refundable balance,
    you can issue further partial refunds up to the total settled amount. Each
    additional refund still requires the intent to be within 30 days of its creation
    date, and each call must use a unique `idempotencyKey`.

    ```bash theme={null}
    curl -X POST https://api-sandbox.circle.com/v1/paymentIntents/e2e90ba3-9d1f-490d-9460-24ac6eb55a1b/refund \
      -H "Authorization: Bearer $API_KEY" \
      -H "Content-Type: application/json" \
      -d @body.json
    ```

    ```json theme={null}
    {
      "idempotencyKey": "b1d4ef72-3c8f-4cb2-9f0d-3c6f9e2a1d77",
      "destination": {
        "chain": "BASE",
        "address": "0xcd7475eaed9ee9678cf219cec748e25aba068a69"
      },
      "amount": {
        "currency": "USD"
      },
      "toAmount": {
        "amount": "0.25",
        "currency": "USD"
      }
    }
    ```
  </Step>
</Steps>

## See also

* [Stablecoin payins and payouts](/circle-mint/concepts/stablecoin-payins-and-payouts):
  Concepts for the refund window and the payment intent state machine.
* [Receive a stablecoin payin](/circle-mint/howtos/receive-stablecoin-payin):
  Accept the payment that you later refund.
* [Travel Rule compliance](/circle-mint/references/travel-rule-compliance):
  Travel Rule data model for Stablecoin Payouts.
