> ## Documentation Index
> Fetch the complete documentation index at: https://boxo.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Refunds

> Refund a host app payment from a miniapp and track its result

A miniapp asks the host app to refund a payment with `refund_request`. The host app returns the money to the user and reports the result with `refund_status`. A payment can be refunded partially and more than once, up to the amount that was charged.

> **refund\_request**
>
> **Miniapp → Host app.** Asks the host app to refund an amount of a payment.

> **refund\_status**
>
> **Host app → Miniapp.** Reports the state of a refund, ending with a final state.

## Flow

```mermaid theme={"system"}
sequenceDiagram
  participant M as Miniapp backend
  participant P as Boxo Platform
  participant H as Host app backend
  M->>P: refund_request
  P->>H: refund_request
  H-->>P: 200 {}
  P-->>M: 200 {}
  Note over H: Refund is processed
  opt Optional progress update
    H->>P: refund_status (processing)
    P->>M: refund_status (processing)
    M-->>P: 200 {}
  end
  H->>P: refund_status (completed, failed or cancelled)
  P->>M: refund_status (completed, failed or cancelled)
  M-->>P: 200 {}
```

## Refund states

| State | Final | Meaning |
| - | - | - |
| `pending` | No | The refund was received but not started. Sending it is optional. |
| `processing` | No | The refund is in progress. Sending it is optional. |
| `completed` | Yes | The money was returned to the user. |
| `failed` | Yes | The refund could not be made, including when the host app rejects it. |
| `cancelled` | Yes | The refund was cancelled before it completed. |

> [!NOTE]
>
> Final states never change. The host app must send exactly one final state for every refund it receives.

## `refund_request`

Asks the host app to refund an amount of a payment it charged.

**Direction:** Miniapp → Host app

### Payload

**refund\_id** `string` *required*

Unique id of this refund, generated by the miniapp. It is the idempotency key: the same `refund_id` always means the same refund.

**order\_payment\_id** `string` *required*

The host app payment to refund, as returned by the host app's create order payment endpoint.

**miniapp\_order\_id** `string` *required*

The miniapp order the payment belongs to, as sent in the create order payment request.

**amount** `string` *required*

Amount to refund, as a string with 2 decimals.

> [!TIP]
>
> `amount` can be less than the payment amount. A payment can receive several refunds, as long as their total does not exceed the amount charged.

**currency** `string` *required*

ISO 4217 currency code. Always the currency of the original payment.

**reason** `string`

Optional human-readable reason, for support and reporting.

The miniapp sends it through `POST /api/v1/events/miniapp/`, and the host app's Event Receiver answers with an empty body:

```json Request theme={"system"}
{
  "app_id": "app_XXXXXX",
  "client_id": "host_XXXXXXXXXXXX",
  "event_type": "refund_request",
  "external_event_id": "0b8f2c1e-6a4d-4c8e-9a52-3f1d7e2b9c40",
  "payload": {
    "refund_id": "0b8f2c1e-6a4d-4c8e-9a52-3f1d7e2b9c40",
    "order_payment_id": "8X566iHGnpUxHXPX3FH0iDsXUVn9ku16xJGQ",
    "miniapp_order_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "amount": "25.00",
    "currency": "USD"
  }
}
```

```json Response theme={"system"}
{}
```

### Receiver must

> [!TIP]
>
> Deduplicate on `refund_id` and never refund the same `refund_id` twice.

> [!TIP]
>
> Respond `200` with `{}` straight away, before processing the refund.

> [!TIP]
>
> Send `refund_status` once the result is known, ending with a final state.

## `refund_status`

Reports the state of a refund to the miniapp that requested it.

**Direction:** Host app → Miniapp

### Payload

**refund\_id** `string` *required*

The `refund_id` from `refund_request`.

**order\_payment\_id** `string` *required*

The `order_payment_id` from `refund_request`.

**refund\_state** `string` *required*

One of the [refund states](#refund-states).

**amount** `string` *required*

The refunded amount, as a string with 2 decimals. Must match `refund_request`.

**currency** `string` *required*

ISO 4217 currency code. Must match `refund_request`.

**processed\_at** `string` *required*

When the refund reached this state, as an ISO 8601 UTC timestamp.

**failure\_reason** `string`

Why the refund failed or was cancelled. Only for `failed` and `cancelled`.

The host app sends it through `POST /api/v1/events/hostapp/`, and the miniapp's Event Receiver answers with an empty body:

```json Request theme={"system"}
{
  "app_id": "app_XXXXXX",
  "client_id": "host_XXXXXXXXXXXX",
  "event_type": "refund_status",
  "external_event_id": "c2d7a8e4-1f3b-4b6a-8d0e-5a9c3e7f1b22",
  "payload": {
    "refund_id": "0b8f2c1e-6a4d-4c8e-9a52-3f1d7e2b9c40",
    "order_payment_id": "8X566iHGnpUxHXPX3FH0iDsXUVn9ku16xJGQ",
    "refund_state": "completed",
    "amount": "25.00",
    "currency": "USD",
    "processed_at": "2026-08-21T14:31:05Z"
  }
}
```

```json Response theme={"system"}
{}
```

### Receiver must

> [!TIP]
>
> Match the refund on `refund_id`.

> [!TIP]
>
> Ignore updates for a refund that is already in a final state.

> [!TIP]
>
> Respond `200` with `{}`.

## Recommended miniapp behaviour

> **Retrying a failed send**
>
> If sending `refund_request` fails or times out, resend it with the same `refund_id`. The host app deduplicates on `refund_id`, so a resend can never cause a second refund.

> **Missing results**
>
> If no final `refund_status` arrives within a maximum age, for example 7 days, raise an alert for manual follow-up with the host app.

## Supported miniapps

| Miniapp | Sends `refund_request` when | Partial refunds | Integration guide |
| - | - | - | - |
| **Airport Rides** | A booking fails or is cancelled by the provider, the user cancels, a booking change makes the ride cheaper, or support grants a compensation | Yes | [Refunds](https://boxo.mintlify.site/mini-apps/airport-rides/integration.md#refunds) |

> [!TIP]
>
> Other miniapps are added to this table as they adopt the standard. A host app that implements these two events supports all of them.

## Errors

Delivery errors such as a disabled Event Receiver are returned by the Event Bridge API. See [Error Handling](https://boxo.mintlify.site/host-apps/CES.md) in Event Bridge.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.