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

# Bookings

> Confirmed reservations on the partner channel

A **booking** is a confirmed reservation paid for by your customer through your bank's checkout. SafarAPI never touches the card or payment data — your bank captures payment and sends the booking confirmation to SafarAPI with an HMAC‑signed proof of payment.

## Lifecycle

```mermaid theme={"theme":"github-dark-dimmed"}
stateDiagram-v2
  [*] --> CONFIRMED: POST /bookings (with payment_confirmation)
  CONFIRMED --> COMPLETED: travel date + 1 day
  CONFIRMED --> CANCELLED: POST /bookings/{number}/cancel
  COMPLETED --> [*]
  CANCELLED --> [*]
```

Unlike B2C bookings on Safariat, partner bookings have **no PENDING state**: they are created already CONFIRMED because the payment has already been settled.

## Required fields

| Field                  | Meaning                                                                    |
| ---------------------- | -------------------------------------------------------------------------- |
| `quote_id`             | The quote you obtained from `POST /quotes`                                 |
| `partner_reference`    | Your internal booking ID — **unique per partner**, used for reconciliation |
| `traveler`             | Final customer information (first/last name, email, phone, language)       |
| `payment_confirmation` | Proof of payment captured on your side                                     |

The `traveler.customer_reference` is your bank's internal customer ID. SafarAPI hashes it with a per‑partner salt before storing it — no cross‑partner traceability is possible, even in the event of a data leak.

## Payment confirmation

```json theme={"theme":"github-dark-dimmed"}
"payment_confirmation": {
  "bank_payment_ref": "YBANK-PAY-2026-99887",
  "paid_amount_total": "3200.00",
  "paid_amount_net": "2880.00",
  "paid_at": "2026-07-01T14:23:55Z",
  "payment_method": "CARD"
}
```

* `paid_amount_total` — what the customer paid your bank (informative)
* `paid_amount_net` — what your bank owes SafarAPI; **must equal `quote.net_amount`**
* `bank_payment_ref` — your bank's internal payment reference, stored for reconciliation
* `payment_method` — one of `CARD`, `BANK_TRANSFER`, `ACCOUNT_DEBIT`, `CASH`, `WAFACASH`, `OTHER`

## What happens after booking

1. SafarAPI creates a shadow user in Keycloak (federated identity to your bank)
2. The booking is linked to the adventure snapshot (frozen content as your customer saw it)
3. The local agency is notified (system event)
4. The voucher PDF is generated and emailed to the traveller's email
5. The webhook `booking.confirmed` fires to your registered endpoint (if configured)
6. The booking's `partner_paid_amount_net` is added to your outstanding settlement balance

## Cancelling

```bash theme={"theme":"github-dark-dimmed"}
curl -X POST https://api.safarapi.com/api/partner/v1/bookings/MV-ABC123/cancel \
  -H 'Authorization: Bearer sk_live_...' \
  -H 'Idempotency-Key: ...' \
  -H 'X-Timestamp: ...' \
  -H 'X-Signature: ...' \
  -d '{ "reason": "customer_request", "note": "Customer needs to reschedule" }'
```

The response includes:

* `tier_applied` — which cancellation tier matched (frozen on the booking at creation, never moves)
* `refund.net_to_partner` — deducted from your next monthly invoice
* `refund.gross_to_traveler_indicative` — what you should refund your customer (your decision, not enforced)

<Note>
  Refunds are processed entirely through the monthly settlement cycle. SafarAPI does **not** initiate any wire transfer to your bank for cancellations — the refund appears as a negative line on your next invoice.
</Note>

## Listing your bookings

`GET /bookings` returns a paginated list of all bookings made under your partner account. Filters:

* `status` — `CONFIRMED`, `COMPLETED`, `CANCELLED`
* `created_from`, `created_to` — ISO datetime range
* `travel_date_from`, `travel_date_to` — date range
* `cursor`, `limit` — pagination

Pagination is **cursor‑based**. Pass back the `meta.next_cursor` from the previous response to get the next page.
