Partner Integration
Core Chat API Documentation
Partner API reference for integrating hotel search and booking flows.
Onboard now action
- Contact
leo@pageonelab.com. - Brek will issue your partner API key (and sandbox base URL).
- Start testing with Postman or your own HTTP client.
Authentication (API key usage)
Send one of these headers on every request (POST /sessions, POST /events, GET /sessions/{sessionId}):
x-partner-api-key: <partner_api_key>(recommended)Authorization: Bearer <partner_api_key>api-key: <partner_api_key>
Example:
curl "$BREK_BASE_URL/api/partner/v1/core-chat/sessions" \
-H "x-partner-api-key: $BREK_PARTNER_API_KEY" \
-H "content-type: application/json" \
-d '{"actor":{"actorId":"partner_user_001"}}'
POST /events uses the same auth header:
curl "$BREK_BASE_URL/api/partner/v1/core-chat/events" \
-H "x-partner-api-key: $BREK_PARTNER_API_KEY" \
-H "content-type: application/json" \
-d '{"sessionId":"sess_xxx","text":"find me a refundable vegas hotel"}'
Base path
/api/partner/v1/core-chat
Common response headers
x-request-id: request trace IDx-ratelimit-limitx-ratelimit-remainingx-partner-id
POST `/sessions`
EndpointCreates a new partner chat session.
Input variables (field | definition | required):
actor.actorId| Stable end-user ID in your partner system (for profile/history continuity). |Yesactor.timezoneOffsetMinutes| End-user timezone offset in minutes (for date parsing like "tomorrow"). |Nochannel.workspaceId| Optional partner workspace/group identifier used for routing/analytics. |Noconversation.channelId| Optional conversation bucket key from your client app. |Noconversation.id| Optional explicit conversation ID for your own traceability. |Noconversation.threadTs| Optional explicit thread key for your own thread model. |No
Auth header:
x-partner-api-key: <partner_api_key>(orAuthorization: Bearer <partner_api_key>, orapi-key)
Request body:
{
"actor": {
"actorId": "partner_user_001",
"timezoneOffsetMinutes": -480
},
"channel": {
"workspaceId": "partner-workspace"
},
"conversation": {
"channelId": "partner-chat"
}
}
Example response (201):
{
"data": {
"sessionId": "sess_1771456953407_g7p6233d",
"tenantId": "demo-tenant",
"channel": {
"type": "partner_api",
"workspaceId": "partner-workspace"
},
"conversation": {
"id": "partner-chat:sess_1771456953407_g7p6233d",
"channelId": "partner-chat",
"threadTs": "sess_1771456953407_g7p6233d"
},
"actor": {
"actorId": "partner_user_001",
"timezoneOffsetMinutes": -480
},
"createdAt": "2026-02-18T23:22:33.407Z",
"updatedAt": "2026-02-18T23:22:33.407Z",
"events": []
}
}
POST `/events`
EndpointSends one event into an existing session.
Input variables (field | definition | required):
sessionId| Session ID returned byPOST /sessions. |Yesactor.actorId| Optional safety check. If provided, it must match the actor bound to the session. |Notext| Natural-language user message. |Yesfor natural-language flowkind| Explicit event type (for action-based integrations). |No(but required for explicit action-kind calls)payload| Structured action payload (for exampleoptionId,bookingId,paymentMethodId). |No(but required by certainkindvalues)idempotencyKey| Client idempotency token to make write retries safe. |No(required for write kinds listed below)
Auth header:
x-partner-api-key: <partner_api_key>(orAuthorization: Bearer <partner_api_key>, orapi-key)
Request body:
{
"sessionId": "sess_1771456953407_g7p6233d",
"actor": { "actorId": "partner_user_001" },
"text": "Seattle Mar 20-23 1 room refundable",
"payload": {},
"idempotencyKey": "demo:sess_1771456953407_g7p6233d:search:001"
}
Integration rule:
- Persist
sessionIdbyactorIdon your side. Reusing one session across different actors will mix user state.
kind behavior:
- Optional for normal natural-language messages.
- Required only when you explicitly call action kinds (for example:
action_book_option,action_cancel_booking).
Partner UI mapping:
data.result.status= action/state code for your UI logic.data.result.message.text= assistant text to render to end users.data.result.artifacts= structured payload (shortlist, payment setup URL, booking confirmation, etc.).
Idempotency key is required for write kinds:
command_book_by_option_idaction_book_optionaction_confirm_price_changeaction_confirm_payment_cardaction_cancel_booking
Example response (200):
{
"data": {
"sessionId": "sess_1771456953407_g7p6233d",
"event": {
"id": "evt_1771456966998",
"kind": "search_query"
},
"result": {
"traceId": "demo-tenant:partner_api:partner-chat:sess_1771456953407_g7p6233d:evt_1771456966998",
"status": "shortlist",
"message": {
"text": "I found options matching your request in Seattle."
},
"artifacts": {
"shortlist": [
{
"optionId": "3d49d4cb-22b1-4963-9280-508fb1190f5c",
"name": "Inn at the Market",
"pricePerNight": 276.66,
"totalPrice": 980.67,
"currency": "USD",
"refundable": true,
"rating": 4.8
}
]
}
}
}
}
GET `/sessions/{sessionId}`
EndpointReturns current session snapshot and event history.
Input variables (field | definition | required):
sessionId(path) | Existing session ID. Must belong to your partner tenant. |Yes
Auth header:
x-partner-api-key: <partner_api_key>(orAuthorization: Bearer <partner_api_key>, orapi-key)
Example response (200):
{
"data": {
"sessionId": "sess_1771456953407_g7p6233d",
"tenantId": "demo-tenant",
"actor": {
"actorId": "partner_user_001"
},
"events": [
{
"eventId": "evt_1771456966998",
"kind": "search_query",
"resultStatus": "shortlist",
"recordedAt": "2026-02-18T23:22:46.998Z"
}
]
}
}
Golden path example (search -> booking intent -> guest name -> payment setup -> done -> booked)
The sequence below was captured from a real sandbox run on February 18, 2026.
Step 0: Create session
Variables for this step (field | definition | required):
actor.actorId| Stable end-user ID in your partner system. |Yesactor.timezoneOffsetMinutes| User timezone offset in minutes. |Nochannel.workspaceId| Optional partner workspace/group identifier. |Noconversation.channelId| Optional conversation key in your client app. |No
Input (POST /sessions):
{
"actor": {
"actorId": "partner_golden_user_done",
"timezoneOffsetMinutes": -420
},
"channel": {
"workspaceId": "partner-demo"
},
"conversation": {
"channelId": "partner-chat"
}
}
Output (201):
{
"data": {
"sessionId": "sess_1771456953407_g7p6233d",
"tenantId": "demo-tenant",
"channel": {
"type": "partner_api",
"workspaceId": "partner-demo"
},
"conversation": {
"id": "partner-chat:sess_1771456953407_g7p6233d",
"channelId": "partner-chat",
"threadTs": "sess_1771456953407_g7p6233d"
},
"actor": {
"actorId": "partner_golden_user_done",
"timezoneOffsetMinutes": -420
}
}
}
Step 1: Search request
Variables for this step (field | definition | required):
sessionId| Session ID returned in Step 0. |Yestext| Natural-language search request from the user. |YesidempotencyKey| Retry-safe dedupe key from partner side. |Recommended
Input (POST /events):
{
"sessionId": "sess_1771456953407_g7p6233d",
"text": "find me a las vegas hotel from 5/15 to 5/16 that is cheap and refundable",
"idempotencyKey": "demo:sess_1771456953407_g7p6233d:search:001"
}
Output (status=shortlist):
{
"data": {
"result": {
"status": "shortlist",
"message": {
"text": "I found options matching your request in Las Vegas. Matched core filters: refundable only. Sorted by lowest total price first."
},
"artifacts": {
"shortlist": [
{
"optionId": "1375108c-d021-4e45-a54a-e11ef553af07",
"name": "Branding Iron Motel",
"pricePerNight": 98.11,
"totalPrice": 110.26,
"currency": "USD",
"refundable": true,
"rating": 2,
"distanceTo": "2.7 miles from Las Vegas",
"detailsUrl": "http://localhost:3000/book/hotel/69450b14fc4f2dc72399a9ba?..."
}
]
}
}
}
}
Step 2: User asks to book option 1
Variables for this step (field | definition | required):
sessionId| Session ID returned in Step 0. |Yestext| User booking-intent message. |Yes
Input (POST /events):
{
"sessionId": "sess_1771456953407_g7p6233d",
"text": "can you help me book option 1"
}
Output (status=guest_name_required):
{
"data": {
"result": {
"status": "guest_name_required",
"message": {
"text": "Before I book, I need the check-in guest name for room 1: first name + last name exactly as shown on an official ID."
}
}
}
}
Step 3: User provides guest name
Variables for this step (field | definition | required):
sessionId| Session ID returned in Step 0. |Yestext| Guest-name message (for example: "guest name is John Doe"). |Yes
Input (POST /events):
{
"sessionId": "sess_1771456953407_g7p6233d",
"text": "guest name is John Doe"
}
Output (status=payment_setup_required):
{
"data": {
"result": {
"status": "payment_setup_required",
"message": {
"text": "No payment method is set up for this account. Please add a card before booking. Set up here: http://localhost:3000/portal/payment?token=psu_1771456992743_e2634ddd\nPlease reply \"Done\" once you finished set up."
},
"artifacts": {
"payment": {
"setupUrl": "http://localhost:3000/portal/payment?token=psu_1771456992743_e2634ddd"
}
}
}
}
}
Step 3.5: User finishes card setup in payment portal
This happens outside Partner Core Chat endpoints (in Brek payment stack), but shown here for end-to-end clarity.
Variables for this step (field | definition | required):
portalToken| Payment setup token returned inartifacts.payment.setupUrl. |YespaymentMethodId| Payment method token from payment provider. |YescardBrand| Card brand (for examplevisa). |YescardLast4| Last 4 digits of card. |YesexpMonth| Card expiration month. |YesexpYear| Card expiration year. |YessetAsDefault| Whether to set this card as default. |No
Input (POST /v1/hotel-ea/payment-methods/attach on Brek payment backend):
{
"portalToken": "psu_1771456992743_e2634ddd",
"paymentMethodId": "pm_card_visa",
"cardBrand": "visa",
"cardLast4": "4242",
"expMonth": 12,
"expYear": 2030,
"setAsDefault": true
}
Output:
{
"data": {
"status": "ATTACHED",
"paymentMethod": {
"paymentMethodId": "pm_card_visa",
"brand": "visa",
"last4": "4242",
"expMonth": 12,
"expYear": 2030
}
},
"message": "success"
}
Step 4: User returns to chat and says "Done"
Variables for this step (field | definition | required):
sessionId| Session ID returned in Step 0. |Yestext| Completion message after card setup (for example: "Done"). |Yes
Input (POST /events):
{
"sessionId": "sess_1771456953407_g7p6233d",
"text": "Done"
}
Output (status=payment_confirmation_required):
{
"data": {
"result": {
"status": "payment_confirmation_required",
"message": {
"text": "I found your updated card: VISA •••• 4242. Use this card to continue booking?"
},
"artifacts": {
"payment": {
"paymentMethodId": "pm_card_visa",
"cardBrand": "visa",
"cardLast4": "4242",
"expMonth": 12,
"expYear": 2030
}
}
}
}
}
Step 5: User confirms payment and booking
Variables for this step (field | definition | required):
sessionId| Session ID returned in Step 0. |Yestext| Confirmation message (for example: "yes, use this card"). |Yes
Input (POST /events):
{
"sessionId": "sess_1771456953407_g7p6233d",
"text": "yes, use this card"
}
Output (status=booked + confirmationUrl):
{
"data": {
"result": {
"status": "booked",
"message": {
"text": "Booked Branding Iron Motel."
},
"artifacts": {
"booking": {
"bookingId": "A1WDDC",
"confirmationBookingId": "699649fae0ee4bb440ddccf7",
"hotelName": "Branding Iron Motel",
"totalPrice": 110.26,
"currency": "USD",
"confirmationUrl": "http://localhost:3000/my-bookings/699649fae0ee4bb440ddccf7",
"cancelPolicy": "Refundable until 2026-05-15T01:00:00Z"
}
}
}
}
}
More scenarios and outputs
Scenario A: user says "Done" but card is not attached yet
Variables for this scenario (field | definition | required):
sessionId| Existing session ID. |Yestext| Completion message (for example: "Done"). |Yes
Input (POST /events):
{
"sessionId": "sess_1771457039985_uf2ydexs",
"text": "Done"
}
Output (status=payment_setup_required again):
{
"data": {
"result": {
"status": "payment_setup_required",
"message": {
"text": "Sure, you can update your payment method here: http://localhost:3000/portal/payment?token=psu_1771457050204_3d35ca69\nAfter setup, reply \"done\" in this thread and I will verify the new card before booking."
},
"artifacts": {
"payment": {
"setupUrl": "http://localhost:3000/portal/payment?token=psu_1771457050204_3d35ca69"
}
}
}
}
}
Scenario B: user already has a saved card
Variables for this scenario (field | definition | required):
sessionId| Existing session ID. |Yestext| Guest-name message after booking intent. |Yes
Input (POST /events, after guest name):
{
"sessionId": "sess_1771457174011_gavkkfv5",
"text": "guest name is Jane Doe"
}
Output (status=payment_confirmation_required, no setup URL):
{
"data": {
"result": {
"status": "payment_confirmation_required",
"message": {
"text": "Are you ok to pay with VISA •••• 4242?"
},
"artifacts": {
"payment": {
"paymentMethodId": "pm_card_visa",
"cardBrand": "visa",
"cardLast4": "4242",
"expMonth": 12,
"expYear": 2030
}
}
}
}
}
Scenario C: user declines payment confirmation
Variables for this scenario (field | definition | required):
sessionId| Existing session ID. |Yestext| Decline message (for example: "no"). |Yes
Input (POST /events):
{
"sessionId": "sess_1771457174011_gavkkfv5",
"text": "no"
}
Output:
{
"data": {
"result": {
"status": "error",
"message": {
"text": "No problem. I will not charge this card or continue this booking."
}
}
}
}
Error responses
Missing API key (401):
{
"success": false,
"error": "Missing partner API key.",
"code": "missing_partner_api_key",
"details": null,
"requestId": "d813d7e3-ba0b-4a97-899d-0847590d7560"
}
Invalid API key (403):
{
"success": false,
"error": "Invalid partner API key.",
"code": "invalid_partner_api_key",
"details": null,
"requestId": "c75e34ff-aa06-4393-ae7d-cf1d31c3af25"
}
Missing idempotency key for write action (400):
{
"success": false,
"error": "idempotencyKey is required for kind=action_book_option",
"requestId": "2a5ea99c-9884-448f-a442-35a883b64b31"
}
Unknown session (404):
{
"success": false,
"error": "session_not_found",
"details": {
"error": "session_not_found"
},
"requestId": "ca6fc510-87ef-434a-a945-ba19ed0e118f"
}
Retry guidance
- Retry
429and5xxwith exponential backoff. - Reuse the same
idempotencyKeywhen retrying write actions. - Log
x-request-idfor every failed request.
Security requirements
- Keep partner API keys server-side only.
- Use HTTPS/TLS for all requests.
- Do not send raw PCI card data in chat payloads.