> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.westiq.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.westiq.ai/_mcp/server.

# Personas

A **persona** is a per-member behavioral profile — genre affinities, retail
interests, engagement and monetization signals — that shapes [scored serves](/guides/catalog-serve#scored-serve) and [suggestions](/guides/suggestions).
This page covers generating one for a member, and listing the airline's
selectable archetype gallery.

## Generate a persona \[#generate]

`POST /v1/personas/generate` drafts a persona for one member from declared
traveler attributes. It is [session-scoped](/guides/sessions#the-x-session-id-header)
— **requires the `X-Session-Id` header** — and Deep-tier (it makes a model call).
Body (max 16 KiB; each string attribute max 100 chars):

| Field                      | Required | Rules                                                                                                                                      |
| -------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `seatId`                   | yes      | The member's seat.                                                                                                                         |
| `ageBand`                  | yes      | Declared band — a **generation input only**, never the authoritative age tier (that comes from [session setup](/guides/session-setup)).    |
| `travelPurpose`            | no       | The purpose of the trip. Any text is accepted. Recommended values: business, leisure, visiting friends or family, adventure, first flight. |
| `cabinClass`               | no       | The traveler's cabin. Any text is accepted. Recommended values: economy, premium economy, business, first.                                 |
| `groupType`                | no       | The traveler's party. Any text is accepted. Recommended values: solo, couple, family, friends, group.                                      |
| `memberSlot`               | no       | Which member on a shared seat. Omit for solo.                                                                                              |
| `declaredGenrePreferences` | no       | Object of genre → strength (0–100), up to 40 entries.                                                                                      |
| `retailInterests`          | no       | Array of interest labels, up to 20.                                                                                                        |
| `language`, `contentStyle` | no       | Optional preferences.                                                                                                                      |

Send `travelPurpose`, `cabinClass` and `groupType` when you have them; omit
them, or send `null`, when you do not. A value that is sent must not be blank
and is at most 100 characters. The recommended values are suggestions, not a
closed list. A persona generated without one of these fields carries no
declared value for it, and the response omits that property.

```bash
curl -X POST "https://api.staging.westiq.ai/v1/personas/generate" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "X-Session-Id: seat-12A-f3d9c1" \
  -H "Content-Type: application/json" \
  -d '{
        "seatId": "12A",
        "ageBand": "35-44",
        "travelPurpose": "leisure",
        "cabinClass": "economy",
        "groupType": "family",
        "declaredGenrePreferences": { "Drama": 80, "Comedy": 60 }
      }'
```

The `200` response is a `PersonaRecord`:

```json
{
  "schemaVersion": "1",
  "featureSchemaVersion": "1",
  "airlineId": "demo_airline",
  "sessionId": "seat-12A-f3d9c1",
  "seatId": "12A",
  "description": "A leisure traveler who leans into character-driven drama…",
  "embedding": [0.012, -0.043, "…"],
  "generatedAtMs": 1751558490000,
  "genreAffinities": { "Drama": 82, "Comedy": 58, "Action": 0 },
  "retailCategories": ["Noise-cancelling headphones", "Travel wallets"],
  "engagementScore": 71,
  "monetizationPropensity": 44
}
```

* `description` is model-generated free text. `genreAffinities`,
  `retailCategories`, `engagementScore`, `monetizationPropensity` are the
  structured, code-normalized fields — present once the persona is generated
  (`genreAffinities` is filled to zero across the canonical genre vocabulary).
* `embedding` is a similarity vector, useful for archetype/content matching.
* Null-valued fields are **omitted** from the response, not sent as `null` — a
  solo traveler's record simply has no `memberSlot` key, for instance.

> **Note**
>
> **Generation is idempotent per session + member.** Calling generate again for a
> member who already has a persona returns the **same record** (`200`, no new
> model call, no second write) — the record is written once per session and never
> overwritten. To re-profile, use a new session. There is **no rules fallback**:
> if generation genuinely fails, it surfaces as a generic `500 internal.error` —
> quote the `correlationId`.

Errors: `400 session.unresolved`, `401` / `403`, `422 request.validation`
(a required attribute missing/blank, an attribute over 100 chars, too many
`retailInterests`/`declaredGenrePreferences`), `429 rate.limited` over the
[per-client request-rate limit](/guides/errors#rate-limits) (honor the
`Retry-After` header), `500`.

## List archetypes \[#list]

`GET /v1/personas` returns your airline's selectable **persona archetype
gallery** — the pre-computed clusters a seatback UI can offer as a starting
point. It is [airline-scoped](/guides/sessions#endpoints-that-need-no-session):
no `X-Session-Id`, no parameters.

```bash
curl "https://api.staging.westiq.ai/v1/personas" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

```json
{
  "schemaVersion": "1",
  "correlationId": "req_0197c0a1b2c3d4e5f60718293a4b5c6d",
  "archetypes": [
    {
      "featureSchemaVersion": "1",
      "airlineId": "demo_airline",
      "archetypeId": "family-adventurers",
      "label": "Family adventurers",
      "clusterRank": 1,
      "statisticalFingerprint": { "genre:Adventure": 0.71, "retail:Toys": 0.4 },
      "refreshedAtMs": 1751558490000
    }
  ]
}
```

* `archetypeId` is stable within the airline — pass it as a member's
  `archetypeId` in [session setup](/guides/session-setup) to seed their persona.
* `clusterRank` is 1-based (1 = largest/most significant cluster).
* An airline with no seeded gallery gets an **honest empty `archetypes` list** —
  never another tenant's archetypes.

Errors: `401` / `403`, `500`.