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

# Airport Rides Integration

> Host app integration guide for the Airport Rides miniapp: payments, order events, and refunds.

For host app owners integrating the Airport Rides miniapp.

This document covers every request the host app receives from Airport Rides and every request the host app makes about an Airport Rides order: payments, order events, and refunds. It covers payloads, authentication, retries, and the integration flow.

All instructions use the host-app perspective: endpoints exposed by the host app, Boxo Platform endpoints called by the host app, and the data exchanged through each.

## How the integration fits together

Payments and refunds go through the Boxo Platform. Order events are sent by Airport Rides straight to the host app's webhooks URL.

```mermaid theme={"system"}
flowchart LR
  HostApp["Host app"] <-- "Payments and refunds" --> Platform["Boxo Platform"] <--> Miniapp["Airport Rides"]
  Miniapp -- "order.succeeded / order.failed" --> HostApp
```

### Endpoints exposed by the host app

| Endpoint | Method | Purpose | Called by |
| - | - | - | - |
| Create order payment | `POST` | Creates a host-app payment and returns `order_payment_id` | Boxo Platform |
| Get order payment status | `POST` (or `GET`) | Returns the current status of a payment. Airport Rides polls it until the payment is final. | Boxo Platform |
| Order webhooks URL | `POST` | Receives `order.succeeded` and `order.failed` | Airport Rides |
| Event receiver | `POST` | Receives `refund_request` | Boxo Platform |
| Boxo Connect endpoints | — | Identify the traveller. OAuth (get access token + get user data) or Direct. | Boxo Platform |

### Boxo Platform endpoints called by the host app

| Operation | Platform endpoint |
| - | - |
| Report a payment result | `POST /api/v1/orders/complete-order/` |
| Report a refund result | `POST /api/v1/events/hostapp/` with `event_type: "refund_status"` |
| Connect a user (Direct flow only) | `POST /api/v1/connect/` |

### Dashboard settings to confirm

| Setting | Why |
| - | - |
| **Event receiver enabled**, with the host-app receiver URL | Off by default. No `refund_request` is delivered until enabled. |
| Payment endpoint URLs | Create order payment, and get order payment status |
| Order webhooks URL for Airport Rides | Where `order.succeeded` and `order.failed` are sent. Share it with Boxo to configure. |
| `hostapp_client_id` / `hostapp_secret_key` | Used to authenticate calls in both directions |

> [!NOTE]
>
> Boxo must enable Event Bridge for both the host app and Airport Rides. Enabling only one side prevents refund events from being delivered.

## Authentication

**Calls received by the host app** (order webhooks, event receiver, create order payment, get payment status) carry:

```
Authorization: Basic base64({hostapp_client_id}:{hostapp_secret_key})
Content-Type: application/json
```

The host app must verify these credentials on every request. There is no signature over the body.

**Calls made by the host app** to the Event Bridge API use the same Basic credentials. Payment platform endpoints such as `complete-order` are authorized by **IP whitelisting** or **request signaturing** configured in the dashboard.

> [!NOTE]
>
> IP whitelisting and request signaturing are also available for securing server-to-server calls. See [Security measures](https://boxo.mintlify.site/host-apps/SecurityMeasures.md).

## Payments

Ride checkout uses the standard [Boxo Payments](https://boxo.mintlify.site/host-apps/BoxoPayments.md) flow.

### Create order payment request

The Boxo Platform calls the host app's **create order payment** endpoint with the body Airport Rides sends:

```json theme={"system"}
{
  "app_id": "app_XXXXXX",
  "order": {
    "currency": "USD",
    "amount": "45.00",
    "subtotal_amount": "45.00",
    "shipping_amount": "0",
    "discount_amount": "0",
    "tax_title": "",
    "tax_amount": "0",
    "taxes_included": false,
    "note": "",
    "miniapp_order_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "hostapp_user_id": "host-user-1",
    "custom_attributes": {}
  }
}
```

Return `{"order_payment_id": "..."}` with HTTP `200`. The traveller settles that payment through the SDK.

| Field | Meaning |
| - | - |
| `currency` | ISO 4217 code of the charge |
| `amount` | What the traveller is charged |
| `subtotal_amount` | Same as `amount` |
| `shipping_amount`, `discount_amount`, `tax_amount` | Always `"0"` |
| `tax_title`, `note` | Always `""` |
| `taxes_included` | Always `false` |
| `miniapp_order_id` | The Airport Rides order key. Store it with the payment. |
| `hostapp_user_id` | The traveller's `reference` from Boxo Connect |
| `custom_attributes` | Always `{}` |

> [!NOTE]
>
> `miniapp_order_id` is the order id for a new booking. When the traveller pays extra for a more expensive booking change, it is the booking change id. Each paid change is a separate payment with its own `order_payment_id`.

### Report the payment result

After the traveller confirms, call the platform:

```bash theme={"system"}
curl --location --request POST '[BOXO_PLATFORM_SERVER_URL]/api/v1/orders/complete-order/' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "order_payment_id": "{{ORDER_PAYMENT_ID}}",
    "app_id": "{{AIRPORT_RIDES_MINIAPP_ID}}",
    "client_id": "{{YOUR_CLIENT_ID}}",
    "payment_status": "paid"
  }'
```

How Airport Rides reads each status:

| `payment_status` | Effect |
| - | - |
| `created`, `in_process` | Pending. Airport Rides keeps waiting for a final status. |
| `paid` | The payment is complete and the ride is booked with the provider. |
| `cancelled`, `returned` | The payment is cancelled and no ride is booked. |
| `failed`, `process_failed` | The payment failed and no ride is booked. |

Include `payment_fail_reason` with `cancelled` and `failed` statuses for operational diagnosis.

### Get order payment status

If a payment result is not delivered, Airport Rides queries the Boxo Platform, which calls the host app's **get order payment status** endpoint. The endpoint must return the current status (`created`, `in_process`, `paid`, `cancelled`, `returned`, `failed`, or `process_failed`).

> [!WARNING]
>
> The **Get order payment status** endpoint is not optional in practice. Payment results do get lost in transit, and this is the only way a payment stuck mid-flow ever resolves. Otherwise a traveller can be charged and never get a ride.

## Order events

Airport Rides sends order events straight to the host app's **order webhooks URL**, in this envelope:

```json theme={"system"}
{
  "id": "3f1c9b7e-2d4a-4f6b-8e1c-9a7d5b3c2e10",
  "type": "order.succeeded",
  "created": "2026-08-21T14:31:05Z",
  "data": { }
}
```

| Field | Notes |
| - | - |
| `id` | Unique id of the event, stable across retries. Deduplicate on it. |
| `type` | One of the [two event types](#the-two-event-types) |
| `created` | When the event was created, as an ISO 8601 UTC timestamp |
| `data` | The order body. See [Payload reference](#payload-reference). Same shape for both types. |

### The two event types

| Type | Fires when |
| - | - |
| `order.succeeded` | The provider confirmed the ride. `status` is `COMPLETED`. |
| `order.failed` | The ride could not be booked after payment, or the provider cancelled a booking that was in progress. A [`refund_request`](#refunds) always follows. |

### Payload reference

| Field | Type | Notes |
| - | - | - |
| `external_source_payment_id` | string \| `null` | The host app's `order_payment_id` for the original charge |
| `booking_id` | string (UUID) | The Airport Rides booking id |
| `external_id` | string \| `null` | The provider booking reference |
| `status` | string | `PENDING` \| `PROCESSING` \| `COMPLETED` \| `FAILED` \| `CANCELLED` |
| `amount` | decimal string | The ride price |
| `currency` | string | ISO 4217 code for `amount` |

> [!NOTE]
>
> Order events carry no passenger personal data.

### Full example

```json order.succeeded theme={"system"}
{
  "id": "3f1c9b7e-2d4a-4f6b-8e1c-9a7d5b3c2e10",
  "type": "order.succeeded",
  "created": "2026-08-21T14:31:05Z",
  "data": {
    "external_source_payment_id": "8X566iHGnpUxHXPX3FH0iDsXUVn9ku16xJGQ",
    "booking_id": "5b2e8f4a-9c1d-4e7b-a3f6-0d8c2b9e1a47",
    "external_id": "MOZ-48213",
    "status": "COMPLETED",
    "amount": "45.00",
    "currency": "USD"
  }
}
```

```json order.failed theme={"system"}
{
  "id": "a8d4e2c6-7b3f-4a1e-9c5d-2f6b8e0a4d13",
  "type": "order.failed",
  "created": "2026-08-21T14:33:40Z",
  "data": {
    "external_source_payment_id": "8X566iHGnpUxHXPX3FH0iDsXUVn9ku16xJGQ",
    "booking_id": "5b2e8f4a-9c1d-4e7b-a3f6-0d8c2b9e1a47",
    "external_id": null,
    "status": "FAILED",
    "amount": "45.00",
    "currency": "USD"
  }
}
```

### Delivery and idempotency

* Events are sent **after** the booking state change is committed.
* Any non-`2xx` response or timeout counts as a failure. A failed delivery is retried about every 5 minutes for up to 24 hours.
* Retried events keep the same `id`, and `data` is rebuilt from the current booking state on every attempt.
* Delivery failures never affect the booking.

> [!WARNING]
>
> **The webhook handler must be idempotent.** The same event can arrive more than once. Deduplicate on `id` and key records on `booking_id` and `external_source_payment_id`.

## Refunds

Airport Rides implements [Standard Events: Refunds](https://boxo.mintlify.site/events/refunds.md). It sends `refund_request` to the host app's event receiver, and the host app reports the result with `refund_status`.

| When | Amount |
| - | - |
| A booking fails or is cancelled by the provider | The full amount paid |
| The traveller cancels a ride | The refundable amount |
| A booking change makes the ride cheaper | The price difference (partial refund) |
| Support grants a compensation | The compensation amount (partial refund) |

Values Airport Rides puts in the payload:

| Field | Value |
| - | - |
| `order_payment_id` | The charge being refunded. When an order has several charges, each refund targets one of them. |
| `miniapp_order_id` | The `miniapp_order_id` of that charge, as in [Create order payment request](#create-order-payment-request) |
| `refund_id` | Unique per refund. Resends of the same refund keep the same `refund_id`. |

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

See [Standard Events: Refunds](https://boxo.mintlify.site/events/refunds.md) for the full contract, the `refund_status` payload, and the refund states.

## Traveller identity

Login uses [Boxo Connect](https://boxo.mintlify.site/host-apps/BoxoConnect.md) through either the OAuth or Direct flow. **`reference`** in the supplied user data becomes the traveller's identity in Airport Rides and is sent as `hostapp_user_id` in the create order payment request. `custom_attributes` are optional.

> [!WARNING]
>
> `reference` must be **stable for a user across sessions and devices**. If it changes, that traveller's ride history goes with it.

## Integration checklist

**1. Enable Event Bridge**

Request that Boxo enable **Event Bridge** for the host app and Airport Rides, and register the host-app **event receiver URL**.

**2. Register payment endpoints**

Register the host-app **create order payment** and **get order payment status** URLs. Both are required for safe checkout.

**3. Set the order webhooks URL**

Share the host-app **order webhooks URL** with Boxo so that `order.succeeded` and `order.failed` are delivered.

**4. Verify inbound credentials**

Verify Basic `hostapp_client_id:hostapp_secret_key` on every inbound call.

**5. Acknowledge every event**

Return `200` from the order webhooks URL and the event receiver for **every** event, including unsupported types.

**6. Key records on stable ids**

Key payments on `miniapp_order_id` and order events on `booking_id` and `external_source_payment_id`.

**7. Deduplicate refunds on refund\_id**

Never refund the same `refund_id` twice.

**8. Always send a final refund\_status**

Send exactly one final `refund_status` (`completed`, `failed` or `cancelled`) for every `refund_request`.

## Quick reference

| Direction | What | Body | Transport |
| - | - | - | - |
| Airport Rides → host app | `order.succeeded` | `{id, type, created, data}` | Direct webhook to the order webhooks URL |
| Airport Rides → host app | `order.failed` | `{id, type, created, data}` | Direct webhook to the order webhooks URL |
| Airport Rides → host app | Create order payment | `{app_id, order}` | Platform API, to the host-app payment endpoint |
| Airport Rides → host app | Get order payment status | `{app_id, client_id, order_payment_id}` | Platform API, to the host-app status endpoint |
| Airport Rides → host app | `refund_request` | `{app_id, client_id, event_type, payload}` | Event Bridge, to the host-app event receiver |
| Host app → Airport Rides | Payment result | `{order_payment_id, app_id, client_id, payment_status}` | Platform `POST /api/v1/orders/complete-order/` |
| Host app → Airport Rides | `refund_status` | `{app_id, client_id, event_type, payload}` | Event Bridge, `POST /api/v1/events/hostapp/` |

Platform reference: [Boxo Event Bridge](https://boxo.mintlify.site/host-apps/CES.md), [Boxo Payments](https://boxo.mintlify.site/host-apps/BoxoPayments.md), [Boxo Connect](https://boxo.mintlify.site/host-apps/BoxoConnect.md), [Standard Events](https://boxo.mintlify.site/events/introduction.md).


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