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

# The VIP journey

> The whole arc, in order, with the endpoint for each step - from a member's first interest to their score after the experience.

This is the flow our concierge desk actually runs, and the endpoint behind each step. Most
integrations only need the first five; the rest happen whether or not you call anything.

<Note>
  **Nothing here is mandatory.** You can go straight from `GET /v1/offers` to
  `POST /v1/redemptions` and skip the whole interest stage — it behaves exactly as it
  always has. The steps below are what makes the concierge's job possible before the
  points move, rather than after.
</Note>

## At a glance

| #  | Step                                         | Endpoint                               | Who calls it     |
| -- | -------------------------------------------- | -------------------------------------- | ---------------- |
| 1  | Browse experiences                           | `GET /v1/offers`                       | member or server |
| 2  | Register interest — **opens a conversation** | `POST /v1/interests`                   | member or server |
| 3  | Talk to a concierge                          | `POST /v1/conversations/{id}/messages` | member           |
| 4  | Share dates and details                      | `PUT /v1/interests/{id}/intake`        | member or server |
| 5  | Accept terms *(if enabled)*                  | `POST /v1/terms/acceptance`            | member or server |
| 6  | Redeem — **inherits the conversation**       | `POST /v1/redemptions`                 | member or server |
| 7  | Confirmation                                 | `redemption.created` webhook           | —                |
| 8  | Logistics, itinerary, tickets                | `GET /v1/conversations/{id}/messages`  | member           |
| 9  | Live updates                                 | `streamMessages(id)`                   | member           |
| 10 | Score the experience                         | `PUT /v1/redemptions/{id}/feedback`    | member or server |

## 1–2. Interest opens the conversation

A member does not have to spend anything to start talking to a concierge. An **interest**
registers that they want an experience and opens the thread — **no points debited, no
inventory held**.

```bash theme={null}
curl -X POST https://api.expys.com/v1/interests \
  -H "Authorization: Bearer $MEMBER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "offer": "off_123", "preferredDates": ["2026-11-06"], "adults": 2 }'
```

The response carries `conversationId`. That thread is live immediately.

<Warning>
  An interest **holds no stock**. A member who takes a week to decide can still lose the
  last unit — which is honest, where a silent hold would let one undecided member freeze
  inventory indefinitely. Show `availability` from the offer.
</Warning>

## 3–4. Chat, and the intake form

Pass `conversationId` to `sendMessage` and the member is talking to a concierge. Dates,
party size and the rest go through the intake endpoint, which **replaces** the whole block
each time.

The three health fields — dietary, allergies, accessibility — are accepted here and
**never stored**. See [Interests and intake](/guides/intake).

## 5. Terms, if your organisation requires them

Off by default. When Expys enables it, `POST /v1/redemptions` refuses an unaccepted member
with `TERMS_NOT_ACCEPTED` and names the version, so you can open the sheet straight from
the error. See [Terms of service](/guides/terms).

## 6. Redeeming from the interest

```bash theme={null}
curl -X POST https://api.expys.com/v1/redemptions \
  -H "Authorization: Bearer $MEMBER_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "offer": "off_123", "interest": "req_abc" }'
```

Passing `interest` means the redemption **inherits that conversation and the intake**. No
second thread opens, and the member keeps one continuous chat from first curiosity to
post-trip follow-up.

<Warning>
  **`redemption.conversationId` is therefore not the redemption's own id.** For bookings
  made without an interest the two happen to be equal, and clients have relied on that.
  Read the field.
</Warning>

## 7–9. Fulfilment

Everything from here is our concierge team working, and reaches you without you asking:

* **`redemption.*` webhooks** for every status transition
* **`conversation.message_created`** for each concierge reply, with `hasAttachments` when
  they send tickets or an itinerary
* **`streamMessages(conversationId)`** for the live thread in-app

Attachments come back on the message with short-lived signed links — fetch the message
again rather than storing the URL. See [Conversations](/guides/conversations).

## 10. Afterwards

```bash theme={null}
curl -X PUT https://api.expys.com/v1/redemptions/req_123/feedback \
  -H "Authorization: Bearer $MEMBER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "rating": 9, "comment": "The guide made the whole trip." }'
```

Only a `completed` redemption accepts it. Averages come back per experience on
`GET /v1/analytics/offers`.

## What each step needs

| Step                             | Credential            | Idempotent                |
| -------------------------------- | --------------------- | ------------------------- |
| Interests, redemptions, terms    | either                | send an `Idempotency-Key` |
| Sending messages, the SSE stream | **member token only** | send a key on writes      |
| Wallet credit, member upserts    | **Org-API-Key only**  | send a key                |

A member token acts as itself. An Org-API-Key names the member with `externalUserID`. See
[Authentication](/authentication).
