Partner Integration

Core Chat API Documentation

Partner API reference for integrating hotel search and booking flows.

Partner key authSession + events modelIdempotency for writes
Versionv1
Endpoints3
Base Path/api/partner/v1/core-chat

Onboard now action

  1. Contact leo@pageonelab.com.
  2. Brek will issue your partner API key (and sandbox base URL).
  3. 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 ID
  • x-ratelimit-limit
  • x-ratelimit-remaining
  • x-partner-id

POST `/sessions`

Endpoint

Creates a new partner chat session.

Input variables (field | definition | required):

  • actor.actorId | Stable end-user ID in your partner system (for profile/history continuity). | Yes
  • actor.timezoneOffsetMinutes | End-user timezone offset in minutes (for date parsing like "tomorrow"). | No
  • channel.workspaceId | Optional partner workspace/group identifier used for routing/analytics. | No
  • conversation.channelId | Optional conversation bucket key from your client app. | No
  • conversation.id | Optional explicit conversation ID for your own traceability. | No
  • conversation.threadTs | Optional explicit thread key for your own thread model. | No

Auth header:

  • x-partner-api-key: <partner_api_key> (or Authorization: Bearer <partner_api_key>, or api-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`

Endpoint

Sends one event into an existing session.

Input variables (field | definition | required):

  • sessionId | Session ID returned by POST /sessions. | Yes
  • actor.actorId | Optional safety check. If provided, it must match the actor bound to the session. | No
  • text | Natural-language user message. | Yes for natural-language flow
  • kind | Explicit event type (for action-based integrations). | No (but required for explicit action-kind calls)
  • payload | Structured action payload (for example optionId, bookingId, paymentMethodId). | No (but required by certain kind values)
  • 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> (or Authorization: Bearer <partner_api_key>, or api-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 sessionId by actorId on 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_id
  • action_book_option
  • action_confirm_price_change
  • action_confirm_payment_card
  • action_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}`

Endpoint

Returns 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> (or Authorization: Bearer <partner_api_key>, or api-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. | Yes
  • actor.timezoneOffsetMinutes | User timezone offset in minutes. | No
  • channel.workspaceId | Optional partner workspace/group identifier. | No
  • conversation.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. | Yes
  • text | Natural-language search request from the user. | Yes
  • idempotencyKey | 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. | Yes
  • text | 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. | Yes
  • text | 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 in artifacts.payment.setupUrl. | Yes
  • paymentMethodId | Payment method token from payment provider. | Yes
  • cardBrand | Card brand (for example visa). | Yes
  • cardLast4 | Last 4 digits of card. | Yes
  • expMonth | Card expiration month. | Yes
  • expYear | Card expiration year. | Yes
  • setAsDefault | 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. | Yes
  • text | 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. | Yes
  • text | 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. | Yes
  • text | 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. | Yes
  • text | 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. | Yes
  • text | 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 429 and 5xx with exponential backoff.
  • Reuse the same idempotencyKey when retrying write actions.
  • Log x-request-id for 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.