Sessions & Member Locators
Sessions & Member Locators
The X-Session-Id header, seat/member locators, and the age-tier model the personalization endpoints share.
The personalization endpoints work in terms of a passenger session and the members seated within it. Search and events don’t need any of this; the theme, catalog-serve, suggestions, enrichment, and persona endpoints do. This page defines the three shared concepts once — the per-endpoint guides link back here rather than repeat them:
- the
X-Session-Idheader that names the passenger session, - the
seatId/memberSlotlocators that name a member within it, and - the age tiers that gating is expressed in.
Your credential still carries your airline (see Authentication). Everything on this page is a within-tenant locator — it selects which of your own airline’s sessions, seats, and members to act on. It never crosses airlines and never elevates privilege: a request can only ever reach the airline its credential is bound to.
The X-Session-Id header
Five endpoints are scoped to a single passenger session and require the
X-Session-Id request header:
The value is the seatback passenger session id — the same identifier your
client puts in the sessionId field of behavioral
events. It is stable for the life of one passenger’s
session, so every call for that passenger — binding members, generating a
persona, scoring the catalog, requesting suggestions — carries the same value
and is threaded together server-side.
The personalization endpoints identify titles by integer titleId
(2041), not the prefixed "M:2041" string that search
results carry — the integer is the numeric part of that id.
Value rules
The header value becomes part of a storage key, so it has the same strict shape
as an event sessionId, plus one addition:
- 1–128 characters.
- No
#(the key delimiter) and no control characters. - No
/. - Must not begin with
apx_(a reserved identity prefix).
Generated ids — a UUID, or a pattern like seat-12A-<hex> — are always safe.
Pre-validate in your client so a bad value never reaches the wire.
When the header is missing or invalid
The request fails closed with 400 session.unresolved — before any work is
done, and never by silently falling back to a non-session default:
session.unresolved is in the standard error envelope — branch
on code, not on the message text.
SSE endpoints name the session in the URL
The two server-sent-events routes are also session-scoped, but they take the
session id as the {id} path segment, not the header:
They do not read X-Session-Id. The path value follows the same key-safety
rules above (the / rule is moot — the URL structure handles it), and a
missing or unsafe value fails the same way, 400 session.unresolved. Both
routes are covered in the session events guide.
Endpoints that need no session
POST /v1/search, POST /v1/events, GET /v1/theme, GET /v1/catalog/serve
(the unscored read), and GET /v1/personas (the archetype gallery) are
airline-scoped, not passenger-session-scoped. They take no X-Session-Id
header. Sending one is harmless; it is simply ignored.
Seat & member locators
Within a session, a member is identified by seat and slot:
Both are passed as query parameters on GET /v1/catalog/serve and as body
fields on the scored/personalization POSTs. Like X-Session-Id, they are
within-tenant locators — a way to say which member, never a trust assertion.
Locators fail closed, never loud. An unknown seat, an unbound member, or a
malformed/crafted locator resolves to the Unknown age tier — treated as
the most restrictive (child-safe) set — and returns results accordingly. It
is never a 4xx/5xx. So restricted or empty results from an
unrecognized locator are the designed fail-closed behavior, not a failure to
debug. Bind your members first (below) to get their real tier.
Age tiers
Gating is expressed in four tiers. A member’s tier is resolved server-side from the age band you bind at session setup; it is never sent per-request.
Two rules follow from this and matter for integration:
- Unknown age resolves to Child, not Adult. Until a member is bound with a known age band, they see the child-safe catalog. This is deliberate child-safety, not a cold-start bug.
- A title with a missing or unrecognized rating is excluded for every non-adult tier — guessed out, never in.
To give a member their real tier, bind the seat’s roster once per session with
POST /v1/personas/session, which takes each member’s
seatId and ageBand and resolves an authoritative tier server-side. How each
endpoint applies a resolved tier (filtering, empty responses, exclusion
counts) is documented in that endpoint’s own guide.