Skip to content

PTX Channel Manager — OTA API Technical Request (for Partner Engineering Teams)

Audience: OTA connectivity / integrations engineering teams (Booking.com Connectivity, Agoda YCS, Expedia Partner Solutions / EQC, Traveloka Connect).
Purpose: Engineer-to-engineer brief describing the endpoints, webhooks, auth, and test assets PTX-CM needs to move off session-scraping and onto certified APIs.
Companion doc: docs/ota-partner-application.md (business/compliance). This document is the technical annex.
Prepared by: PTX-CM Integrations Engineering
Version: 1.0
Date: 2026-04-24


1. TL;DR for partner engineers

We are a multi-property channel manager (NestJS 11 + PostgreSQL + Redis/BullMQ). We currently integrate with your platform via session-based scraping — it works but it is fragile and noisy for your infra. We would like to move our traffic onto your official APIs.

Please help us with the items in §9 What we need from you. Everything else in this document exists so your team can size the request and trust our client implementation.


2. Our side in one diagram

  Property operator UI  ─┐
  Internal schedulers   ─┼─►  NestJS API  ──►  BullMQ (per-OtaAccount queue)  ──►  OTA Adapter  ──►  Partner API
                         │          ▲                                                    │
                         │          │                                                    ▼
                         └──────────┴────────────  Postgres  ◄──  Webhook receiver  ◄────┘
  • One queue per OtaAccount (property × OTA) — isolates noisy neighbours
  • Every outbound call carries X-Request-Id + clientRequestId (for idempotency)
  • Every inbound webhook is persisted raw before ACK — replay is a SELECT, not a re-fetch

3. Scope — capabilities we are asking for

3.1 Availability (write)

  • Push room-level availability (availableCount per ratePlanId × date).
  • Date-range updates (we would prefer 365-day windows but will chunk to whatever max you support).
  • Ideally delta updates only, with a "full resync" endpoint we call once per onboarding + weekly drift check.

3.2 Rates (write)

  • Push base rate + up to N derived rate plans per room type.
  • Support for per-date overrides, weekday patterns, and restrictions (MinLOS, MaxLOS, CTA, CTD, Stop-Sell).
  • Currency: publisher currency of the property (OTA already knows this — we do not override).

3.3 Reservations (read + webhook)

  • Preferred: push webhook on booking create / modify / cancel (see §5).
  • Fallback: polling endpoint with since=<ISO8601> cursor — used only if webhook delivery is unhealthy.
  • Payload must include: OTA booking id, property id, rate plan id, room type id, guest contact, arrival/departure, nightly rates, taxes/fees breakdown, payment model (merchant vs hotel collect), cancellation policy snapshot, special requests.

3.4 Room-type & rate-plan mapping (read)

  • One-time read of the property's taxonomy so we can map to our internal RoomType + RatePlan entities.
  • We want immutable IDs on your side; if yours change, please expose an ID-history endpoint.

3.5 Content (read, optional Phase 2)

  • Static property content: descriptions, amenities, photos, policies — so we can reconcile cross-OTA differences and surface them to the operator.

3.6 Reviews (read + write, Phase 2)

  • Pull review list + detail; post operator replies. OK if behind separate certification.

3.7 Out of scope (explicitly not requested)

  • Search / shopping APIs
  • Payment tokenisation
  • Partner-side finance or invoicing endpoints
  • Any end-traveller PII beyond the booking itself

4. Authentication — what we can support

Ranked from most-preferred to least:

  1. OAuth2 client-credentials (machine-to-machine, per OtaAccount). Rotating client secret. Scopes per resource.
  2. OAuth2 authorization-code (user consent flow) — fine if the property owner must explicitly consent; we store refresh tokens encrypted.
  3. Mutual TLS — we can provision a client cert per environment.
  4. Long-lived API key in Authorization header — acceptable if rotatable + scoped.
  5. HMAC request signing (X-Signature: sha256=...) — acceptable standalone or layered over any of the above.

All secrets are stored AES-256-GCM at rest, one KMS key per env. Never logged, never sent to the browser.

5. Webhooks — what we can consume today

  • Transport: HTTPS POST, TLS 1.3, JSON body (application/json).
  • Endpoint shape: https://webhooks.<our-domain>/ota/{partner}/{event} — one per event family, partner-agnostic.
  • Auth options we support receiving:
    • HMAC over raw body (X-Signature header, secret per OtaAccount)
    • mTLS client cert
    • Bearer token (static, rotatable)
  • Response contract: we ACK with 2xx only after we have durably persisted the raw payload. Processing is async downstream.
  • Retry expectation from partner side: exponential backoff, at-least-once delivery, include a stable eventId so we can dedupe.
  • IP allow-list: we can provide our static egress IPs; we ask for yours so we can allow-list inbound.
  • Replay endpoint (nice-to-have): a partner-side endpoint we can call to ask "replay events between T1 and T2 for propertyId" after any outage on our side.

6. Client behaviour you can rely on

6.1 Idempotency

Every write request carries Idempotency-Key: <uuid-v4> (header name negotiable). Retries of the same logical mutation use the same key. We expect your side to return the original result on duplicate keys within a reasonable window (24h OK).

6.2 Retry & backoff

  • Base: 1s, 2s, 4s, 8s, 16s, cap 30s, ±25% jitter
  • Max 5 attempts for idempotent writes; 0 retries for 4xx except 408/425/429
  • Honour Retry-After on 429 / 503 exactly — we do not retry earlier

6.3 Error classification we apply

HTTPOur treatment
2xxPersist, emit business event
400 / 422Reject locally, surface to user, no retry
401 / 403Refresh token once → if still failing, mark OtaAccount.status = EXPIRED and alert
404Treat as stale, log, no retry
409Surface as conflict, manual resolution path in UI
429Honour Retry-After, pause queue
5xxRetry with backoff, then circuit-break the account
Network timeoutSingle retry with new correlation id, then backoff

6.4 Rate-limit discipline

  • We publish ourselves a per-OtaAccount concurrency budget and a per-endpoint token bucket.
  • We read and respect all of: X-RateLimit-Remaining, X-RateLimit-Reset, Retry-After.
  • If you document stricter limits than standard headers, please send us the doc — we will encode them.

6.5 Circuit breakers

Per-OtaAccount. Trips on sustained 5xx or auth failure, pauses traffic, alerts operator. Recovery is manual + health-check probe.

6.6 Observability / traceability

  • We send X-Request-Id: <uuid> on every outbound call.
  • We attach X-Client-Version: ptx-cm/2.9.x and X-Partner-Account: <opaque-ptx-id>.
  • We store response headers + body (redacted for PII) for 30 days for joint-debug.
  • Please echo our request id in your logs, and share your partner-side request id in the response (X-Partner-Request-Id or similar) so we can join logs during incidents.

7. Data model & field expectations

For each resource we request, please supply:

  • Schema: OpenAPI 3.x (preferred), JSON-Schema, or a versioned PDF.
  • Semantics: meaning of nullable vs missing, timezone of date fields, rounding rules for money, currency codes (ISO 4217), language codes (BCP 47).
  • Identifiers: are they global, or scoped per property?
  • Enum stability: do enum values ever change? If yes, what is the deprecation window?
  • Versioning policy: URL-path, header, or content-negotiation? Deprecation lead time?

8. Testing assets we need

  1. Sandbox environment with at least one test property pre-provisioned.
  2. Ability to create test bookings in sandbox (either self-service UI or a partner endpoint) so we can exercise the reservations pipeline end-to-end.
  3. Fault-injection hooks (nice-to-have): force 429, force 500, force auth-expired for contract-testing.
  4. Postman / Insomnia collection or equivalent — optional but speeds onboarding by weeks.
  5. Webhook test harness: ability to trigger synthetic webhook events to our sandbox receiver.
  6. Certification checklist, scored, so we know exactly what must pass before production.

9. What we need from you — action list

#ItemPriorityOwner (partner side)
1Grant sandbox credentials (per §8.1)P0Connectivity onboarding
2Share OpenAPI / schema docs for scopes in §3.1–§3.4P0API team
3Confirm auth method from §4 that your platform supportsP0Security / API team
4Webhook registration flow + signing key issuanceP0Connectivity ops
5Published rate limits per endpointP0API team
6Certification checklist + test cases we must passP1Certification team
7Incident escalation channel (email + Slack / Teams)P1Support
8Partner-side egress IPs (for our inbound allow-list)P1Infra
9Content + Reviews API access (Phase 2)P2Product
10Replay endpoint for webhook gaps (§5)P2API team

10. Proposed timeline

WeekMilestone
0Kick-off call, NDA if required
1Sandbox credentials issued, OpenAPI shared
2–3Adapter implementation against sandbox, contract tests green
4Webhook receiver + replay tested end-to-end
5Certification test cases executed, report sent for partner review
6Go-live on pilot property (1 property, 1 OTA)
7–8Ramp to 10 properties, monitor metrics in §11
9+Fleet-wide rollout

We can compress this if your team can too; we will not push faster than your certification allows.

11. How we will measure success together

  • Sync success rate per OtaAccount ≥ 99.5% (excluding 4xx caused by bad operator input)
  • Push latency p99 ≤ 30s for availability, ≤ 5min for bulk rates
  • Booking ingest latency p99 ≤ 60s via webhook, ≤ 150s via polling fallback
  • Zero overbooking incidents attributable to PTX-CM
  • Mean time to recover from partner-side incident ≤ partner's own SLA

We are happy to share a weekly dashboard with partner ops during ramp.

12. Sample request snippets (what our client will send)

12.1 Availability push (illustrative, partner shape will differ)

http
POST /v1/availability HTTP/1.1
Host: api.partner.example
Authorization: Bearer <token>
Content-Type: application/json
Idempotency-Key: 7f2c5d2e-2d1a-4a1c-9e6a-5c3b2a1f0d4e
X-Request-Id: 3f9b8e16-7a0c-4d2b-8b21-9a6f0e4b1c77
X-Client-Version: ptx-cm/2.9.3

{
  "propertyId": "P-000123",
  "updates": [
    { "ratePlanId": "RP-STD", "roomTypeId": "RT-DLX", "date": "2026-05-01", "available": 4 },
    { "ratePlanId": "RP-STD", "roomTypeId": "RT-DLX", "date": "2026-05-02", "available": 3 }
  ]
}

12.2 Webhook we will accept from you

http
POST /ota/{partner}/reservation.created HTTP/1.1
Host: webhooks.ptx.example
Content-Type: application/json
X-Signature: sha256=9a7b8c...
X-Event-Id: evt_01HYZ3QF0G7B9PJMV4EE3W5T0X

{
  "eventId": "evt_01HYZ3QF0G7B9PJMV4EE3W5T0X",
  "eventType": "reservation.created",
  "occurredAt": "2026-05-01T07:15:22Z",
  "propertyId": "P-000123",
  "reservation": { /* full reservation per §3.3 */ }
}

12.3 Error we can round-trip cleanly

http
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1714551682
X-Partner-Request-Id: prt_req_5f4a

{ "error": { "code": "rate_limited", "message": "slow down", "docsUrl": "https://..." } }

13. Questions we have for your team

  1. Which auth methods in §4 are supported in sandbox vs production?
  2. What is the maximum date range per availability push?
  3. Are propertyId / roomTypeId / ratePlanId globally unique or scoped?
  4. What is the webhook delivery SLA + retry policy on your side?
  5. Is there a bulk endpoint we should use for onboarding (full resync), distinct from steady-state deltas?
  6. Do you support partial updates or must we always send full objects?
  7. What is your published versioning + deprecation policy?
  8. Is there an idempotency-key header you already honour? If not, what would you accept?
  9. What is the certification lead time from "ready to test" → "live"?
  10. Who is our single point of contact during ramp-up?

14. Contacts on our side

RoleNameEmail
Integrations engineering leadto be filledto be filled
On-call rotationto be filledto be filled
Security contactto be filledto be filled
Business / commercialto be filledto be filled

Production egress IPs, sandbox webhook URL, and PGP key available on request.


Unresolved questions (internal, for PTX-CM team)

  • Confirm exact max date-range our availability push supports after the BullMQ chunking change (§3.1).
  • Decide whether Phase 2 content/review scopes (§3.5–§3.6) are requested in the first partner call or deferred.
  • Finalise single point-of-contact names in §14 with the ops lead.
  • Confirm static egress IP list with infra (§9 row 8 dependency).
  • Validate §12 sample payloads against our current NestJS adapter contract to make sure shape matches what we actually send.

PTX Channel Manager — Internal Documentation