Data contracts
This page specifies the reference data Edge Portal expects your systems to supply, and the events it writes back — the answer to "what feed do you take, and what do we get out?". If your reservation system can provide these entities, everything described in the overview works on your real bookings, guests, and itineraries.
Two rules apply throughout:
- This is the canonical baseline model. Field names below are the platform's canonical shapes; per-tenant mappings from your reservation system's payloads onto them are agreed in the interface contract during implementation workshops. The model is extendable per tenant — see Extending the model. Whatever you cannot supply is either entered on the portal or omitted where optional.
- Conventions: dates are ISO
YYYY-MM-DDand timestamps ISO 8601 with timezone, currency codes are ISO 4217, money is decimal in the booking currency, and identifiers are stable opaque strings from your system — the portal never interprets them.
Inbound: booking feed (read-only)
The feed from your reservation system into the portal. The portal renders from this feed and mutates nothing in it — all guest and agent actions flow back through write-back events. The feed can be pushed on change or pulled by the platform on a schedule; itinerary updates propagate to the live change feed either way.
Booking
The booking header — the unit everything else is scoped to.
| Field | Required | Description |
|---|---|---|
reference | Yes | Stable booking reference the guest knows, e.g. MT-882401. It identifies the booking but is not an authentication credential — portal access requires the separately defined authentication flow |
product.code / product.name | Yes | Tour or cruise product, e.g. MERBOI-260812 / Best of Italy |
product.destination_region | Yes | Drives rules-based variants — for example which pre-travel form applies |
product.ship / product.duration_days | No | Display |
departure_id | Yes | Departure identifier — itinerary variance is per departure |
departure_date / return_date | Yes | Travel window; all readiness deadlines anchor to departure_date |
channel | Yes | direct | agent — agent-booked guests get a read-only portal, and reminders target the agent until the configured handover point |
status | Yes | confirmed | cancelled | on_request |
currency | Yes | ISO 4217 booking currency, e.g. GBP |
cabin_or_room | No | Assigned cabin or room, when applicable |
Agent of record
Present when channel is agent. Powers the read-only trade mode and the agent-phase reminder audience.
| Field | Required | Description |
|---|---|---|
agency_name | Yes | Display and reminder addressing |
agency_code | No | Your identifier for the agency |
consultant_name / email / phone | No | The consultant reminders are addressed to |
Passengers
One record per traveler on the booking.
| Field | Required | Description |
|---|---|---|
passenger_id | Yes | Stable identifier — write-back events reference it |
given_names / surname | Yes | Identity as held in your system |
lead | No | Marks the lead passenger |
date_of_birth / email / phone | No | Contact and identity detail |
passport | No | document_number, nationality, expiry_date — pre-fills the passport step; captured on the portal when absent |
forms[] | No | Pre-travel form status per variant: variant_code, status (not_started | in_progress | complete), completed_at — the variant served is selected by destination rules |
dietary | No | Current dietary requirements, editable on the portal |
Itinerary
The per-departure itinerary, including departure-level variance. Supplying it on change keeps the live feed current.
| Field | Required | Description |
|---|---|---|
version | Yes | Increments on every change — drives the change feed and "updated 2 minutes ago" |
updated_at | Yes | Timestamp of the last change |
days[].day_number / days[].title | Yes | Day-by-day structure |
days[].date / days[].description | No | Detail content |
days[].released | No | Progressive release flag — summary-only until true |
days[].variance_note | No | Departure-specific deviation from the brochure itinerary (mooring, venue, timing) |
days[].choice | No | Selectable option set for the day: select_by date, options[], selected |
change_events[] | No | Recent changes for the live feed strip: occurred_at, day_number, summary, detail |
Freshness. How quickly a reservation-system change appears on the portal follows from the feed mode: a feed pushed on change updates the live itinerary in near real time, while a pulled feed is as fresh as its pull interval. The freshness target — and the pull interval where pulling is chosen — is agreed per tenant in the interface contract. Either way the portal shows the honest updated_at ("updated 2 minutes ago"), never an implied freshness the feed does not have.
Flights
Advised or booked air segments. Availability lookups stay on your side — the feed carries the resulting segments only.
| Field | Required | Description |
|---|---|---|
flight_number / origin / destination / date | Yes | Segment identity |
carrier / departure_time / arrival_time | No | Display |
source | Yes | operator_booked | self_booked — self-booked flights are advised by the guest for transfer planning |
transfer_confirmed | No | Whether a transfer is arranged against this segment |
Payments
Payment schedule and received payments. Receipts flowing through this feed are what let the portal regenerate the invoice instantly after every payment.
| Field | Required | Description |
|---|---|---|
gross_total | Yes | Booking total in the booking currency |
balance_due_date | No | Anchors the final-payment readiness deadline |
schedule[] | Yes | Instalments: label, amount, due_date, status (due | paid | overdue) |
received[] | No | Payments received: received_at, amount, method, receipt_reference |
card_surcharge_pct | No | Card surcharge where applicable in your market |
local_rail | No | Reference details for a local payment rail where one is offered — for example a BPAY biller code and customer reference |
Processing versus registration. This feed and the payment_registration write-back event carry payment records, not card transactions. When the guest pays on the portal with a method Edge Pay hosts, processing runs on the platform's payment stack: Edge Pay pages processed by the Kaptio Pay service, with per-currency merchant-account routing and per-currency 3D Secure policy (see Brands, currencies & 3DS). Card details stay on that path — captured in gateway-hosted fields — and do not transit your reservation system; see Payment security. Once Kaptio Pay has processed that payment, the portal emits payment_registration so your system records the result: your payment API is the write-back target, not the processing path. Local rails advertised via local_rail are reference details for payment outside the hosted card session; they are not processed by Kaptio Pay. Those receipts still arrive as received[] on this feed and as payment_registration when the portal is the system that learned of them.
Optional extras
Catalog references for extras and upsell offers applicable to the departure. Purchases register back through the write-back events, typically onto your existing upsell API.
| Field | Required | Description |
|---|---|---|
extra_code / name / price | Yes | Offer identity and unit price |
category / description | No | Display |
price_basis | No | per_person | per_booking | per_item |
selected | No | Already purchased on this booking |
Pricing sources. An extra is priced in one of two ways, selected per extra in the interface contract — not inferred from a missing price:
- Catalog / rate-table. The offered unit price is the
priceon this feed. Rate-table products derive that figure from ingested tables (age bands, trip value, duration) before the feed is supplied. - Live quote. At selection time the portal calls the provider quoting API configured for that extra. The catalog row still identifies the extra (
extra_code,name,price_basis);priceon the feed is indicative or omitted only where the interface contract says the quote is authoritative. The bound quote amount is whatextras_registrationwrites back.
Travel insurance is the canonical example and works both ways. In both cases selection and purchase follow the standard extras flow, registering back through extras_registration.
Outbound: portal write-back events
Everything a guest or agent does on the portal is written back to your systems as an event. Delivery is at-least-once: consumers must deduplicate by event_id before applying side effects, so receiving the same event more than once never repeats the mutation — this matters most for payment and extras registrations.
Delivery semantics. Delivery targets and transport are agreed per tenant in the interface contract — typically HTTPS POSTs onto your existing endpoints (payment registration and upsell registration are the common cases), authenticated with per-tenant credentials held in the platform's secret vault, never in configuration. A delivery counts as acknowledged on a 2xx response received within the timeout agreed in that contract (the Journeys webhook default of 10 seconds is the reference starting point). Non-2xx responses and timeouts are retried with exponential backoff until the retry window in the contract elapses; whether permanent client errors (4xx) stop retries early is also fixed in that contract. Because retries can reorder arrivals, consumers should not assume events arrive in order: order by occurred_at where sequence matters, and persist and check event_id before applying side effects.
Event envelope
| Field | Required | Description |
|---|---|---|
event_id | Yes | Globally unique — the idempotency key for at-least-once delivery |
booking_reference | Yes | The booking the event belongs to |
passenger_id | No | Set when the event concerns one passenger; null for booking-level events |
occurred_at | Yes | When the action happened on the portal |
actor.role | Yes | guest | agent | system — agent-booked guests are read-only in the trade model, so guest-actor mutation events only occur on direct bookings or after handover |
actor.identifier | No | Pseudonymous portal session subject (e.g. a hashed email address or an agent code) — never a raw credential or plain email |
event | Yes | Exactly one typed payload, discriminated by event.type |
Event types
| Type | Payload highlights | Notes |
|---|---|---|
passport_capture | Parsed document fields plus a check-digit validation result | Capture is on-device: the document image never leaves the guest's device — only the parsed fields are written back |
form_submission | variant_code plus the answer set (question_code, answer) | The variant code identifies the destination-rules form variant served, so the answer set always matches the form your system expects |
dietary_update | The updated dietary string | Per passenger |
transfers_acknowledgment | Acknowledgment flag plus any self-booked flights advised for transfer planning | |
payment_registration | Amount, currency, method, gateway reference, instalment label | Typically maps onto your existing payment registration API; triggers instant invoice regeneration on the portal |
extras_registration | extra_code, quantity, amount, added | removed | Typically maps onto your existing upsell registration API |
reminder_acknowledgment | Reminder id, acknowledged by guest | agent, resolution (completed_on_portal | will_action | disputed) | Feeds the readiness dashboard history and stops repeat sends |
disruption_read_receipt | Notice id and read timestamp | Confirms a guest saw a pushed disruption notice, closing the loop without outbound calls |
Example: passport capture event
{
"event_id": "evt_01J9YB2K7Q4C",
"booking_reference": "MT-882401",
"passenger_id": "pax_02",
"occurred_at": "2026-05-04T09:12:44+01:00",
"actor": { "role": "guest", "identifier": "sha256:9f2c…" },
"event": {
"type": "passport_capture",
"document_number": "553902147",
"surname": "CARTER",
"given_names": "ELENA MARIE",
"nationality": "GBR",
"date_of_birth": "1987-03-22",
"expiry_date": "2031-11-05",
"check_digits_valid": true
}
}
PII posture
The portal persists operational state only — readiness progress, acknowledgment history, delivery tracking. Booking and passenger data renders from the feed, and sensitive capture flows are designed to keep PII in transit rather than at rest on the portal side: the passport document image never leaves the guest's device (parsing happens on-device), and the parsed fields travel to your reservation system as a passport_capture event rather than accumulating in a portal-side document store. Where your regulatory environment requires a stricter split between what the platform may cache and what must be fetched in transit at request time, that split is agreed per tenant in the interface contract. Platform-wide residency and encryption are summarised under Data handling (that page currently describes Salesforce-hosted Edge products); card-data scope is under Payment security.
Extending the model
The baseline above is where every implementation starts; it is not where implementations end. Agreed in the interface contract during implementation workshops, per tenant:
- Tenant-specific fields on any inbound entity — additional booking attributes, passenger flags, or payment metadata your operation relies on.
- Form variants by destination rules — the variant catalog and the rules that select which form a passenger sees are tenant configuration.
- Additional event types — write-back surface beyond the eight baseline events, for actions specific to your operation.
- Mapping onto your existing APIs — where your platform already exposes endpoints (payment registration and upsell registration are common), the corresponding events map onto them rather than requiring new receivers.
For what the portal does with this data, see the Edge Portal overview. For how Edge is hosted and secured, see Architecture & Security.