Channel Manager PRO

Online Travel Agencies — usually called OTAs — are big booking marketplaces like Viator (owned by Tripadvisor) and GetYourGuide. For most tour operators they bring in 30–60% of bookings. Managing them by hand means logging into a separate dashboard for each one, updating availability and prices in every place, and copy-pasting bookings back into your own system. It's slow, error-prone, and when two channels sell the last seat at the same moment you can end up overbooked.
The Channel Manager module connects your Yatra site directly to each OTA. When a booking lands on Viator, it flows straight into your Yatra bookings list. When you change a price or add availability in Yatra, it pushes out to every connected channel. You manage one calendar, not three.
Standalone "channel manager" tools (separate paid products that do this same job) typically cost $99–299 per month. Yatra includes it in the Scale plan at no extra cost.
What you'll need
| Thing | Where to get it |
|---|---|
| Yatra Pro license — Scale tier (Yearly or Lifetime) | Yatra → License |
| Channel Manager module enabled | Yatra → Modules → Channel Manager |
| Partner-program approval from each OTA | See Supported channels below |
| Per-channel API key + webhook signing secret | Issued by the OTA's partner portal |
| Public, HTTPS-accessible WordPress site | Webhooks need to reach you from the public internet |
Bring-your-own credentials, no proxying. All API calls go direct from your WordPress to the OTA. Yatra adds zero markup and never sees your customer data in transit.
What it unlocks
| Surface | What it does |
|---|---|
| Channels tab | List, add, edit, delete one connection per OTA. Per-channel encrypted credentials + sandbox/live mode + commission %, inventory buffer, default price offset. Health badge per channel. |
| Trip mappings tab | Link each Yatra trip to its counterpart product on each OTA. Per-mapping price offset override + sync toggles + bulk operations. |
| Bookings inbox | Every booking received from a connected OTA arrives here, two-phase staged then promoted into the normal Yatra booking list. |
| Sync activity log | Every push, pull, and webhook from the last 90 days. Audit trail with HTTP status, duration, and full error context. |
| Webhook receiver | Public endpoint that accepts signed booking deliveries from each OTA. Always-on regardless of module toggle state — never drops inbound bookings. |
| Hourly safety-net cron | If a webhook misses, the cron pulls bookings for the last 24h and reconciles. |
| Reconciliation report | A single read-only snapshot across every channel — stale mappings, pending booking promotions, sync success/fail counts, breaker states. Suitable for a dashboard refresh button and for external monitoring polling. Details below. |
| Latency report | Per-channel and per-provider average / p50 / p95 / p99 sync durations across 24h and 7d windows. Helps spot a slow OTA before customers do. |
| Inbound webhook IP allowlist | Optional. Restrict the inbound webhook receiver to specific CIDRs (the OTA's documented source ranges, or your corporate proxy) as a second layer on top of the signature secret. |
How it works
Three things happen in the background so your Yatra site and your OTAs stay in sync:
- Push (immediate). When something changes in Yatra — a new booking, a price update, a departure added — Yatra sends that change to every connected OTA within about 30 seconds. If you make a lot of changes at once (a bulk price update, for example), Yatra waits a moment and groups them into one push instead of hammering the OTA with one request per change.
- Pull (every hour). A background job runs hourly to double-check: it pulls the last day's bookings from each OTA (in case a real-time notification was missed), re-sends inventory for every active mapping, and cleans up old activity logs (older than 90 days). This is your safety net.
- Webhooks (inbound). Each OTA notifies your site the moment a booking is made. Yatra checks the notification is genuine (using the secret signing key the OTA gave you, plus a timestamp check so old replays can't be re-used), saves it as a staged booking, and confirms back to the OTA right away so it doesn't time out. A few seconds later Yatra promotes the staged booking into your normal booking list — the same one your direct-website bookings live in.
A few safety mechanisms sit behind those three loops:
- Retries with growing wait times. If a request to the OTA fails (network blip, server error), Yatra retries automatically, waiting a bit longer between each retry. If the OTA explicitly says "slow down" (a
429 Too Many Requestsresponse with aRetry-Afterheader), Yatra waits exactly the amount it asked for. - Failing-OTA isolation ("circuit breaker"). If one OTA keeps erroring repeatedly, Yatra stops calling it for a few minutes, then tries again carefully. The other OTAs keep working. It's the same idea as a household electrical breaker — one bad appliance doesn't take down the whole house.
- Last-seat lock. While Yatra is moving a freshly-received OTA booking into your real bookings list, it briefly locks that trip's seat count so no other channel (or your own website) can sell the same seat at the same instant. This significantly reduces overbooking risk, but doesn't eliminate it 100% — see overbooking realities below.
Supported channels
| Channel | Capabilities | Status |
|---|---|---|
| Viator (Tripadvisor parent) | Push trip content + inventory + pricing · Pull bookings · Signed webhook · Real-time inventory | Built-in adapter |
| GetYourGuide | Push trip content + inventory + pricing · Pull bookings · Signed webhook · Real-time inventory | Built-in adapter |
| Any other OTA with a public API | Same capability set, implemented per request | By request |
Adding a new OTA is a single ProviderInterface implementation; existing Viator and GetYourGuide adapters serve as the templates. If you need a channel that isn't shipped, file an issue describing the OTA + the API they expose and we'll scope the work with you.
Step 1 — Apply for OTA partner access
Each OTA has its own approval flow. Typical lead time: 1–2 weeks for response, 2–4 weeks for full activation. Start this before you start the technical setup.
- Viator: viator.com/supplier — Tour operator → Apply → review takes ~1 week.
- GetYourGuide: supplier.getyourguide.com — Become a supplier → city- and category-fit review.
Once approved, the OTA gives you a partner portal with API key + webhook signing secret generation.
Step 2 — Enable the module
- Open Yatra → Modules.
- Find Channel Manager → toggle on. (Starter / Growth tier shows an Upgrade to Scale CTA instead.)
- A new menu entry Channel Manager appears in the sidebar.
- Database tables are created automatically on toggle-on — no separate install step.
Step 3 — Add your first channel
Open Yatra → Channel Manager → Channels → + Add channel.

Connection card
| Field | Notes |
|---|---|
| OTA channel | Pick the OTA. Locked after creation — switching OTAs is a new channel. |
| Display name | Friendly name shown in the admin UI. Defaults to the OTA's name. |
| Account label (internal) | Distinguish multiple accounts on the same OTA (e.g. "US production", "EU staging"). |
| Currency | The three-letter currency code (e.g. USD, EUR, GBP — this is the international ISO 4217 standard). Must match the currency your products are priced in on the OTA — if Yatra is set to USD and the OTA expects EUR, every price push will fail. |
Pricing & inventory rules card
| Field | Notes |
|---|---|
| Default price offset (%) | Adds (or subtracts) a percentage to your base trip price before pushing to this channel. Use a positive number to cover the OTA's commission so your net stays whole; negative to run a channel-only discount. |
| Commission (%) — informational | What the OTA deducts from each sale. Not sent to the channel — used only to estimate your net revenue in reports. |
| Inventory buffer (seats) | Seats held back from this channel so direct-bookers and other OTAs always have stock. Example: a 20-seat departure with a buffer of 2 will only ever show 18 seats here. |
Channel state card
| Toggle | Notes |
|---|---|
| Enabled | When off, this channel won't push inventory or pricing, and incoming bookings won't be ingested. Logs still record any attempts so you can audit them. |
| Sandbox / test mode | Routes API calls to the OTA's sandbox environment. Always start in sandbox until a test booking has flowed through end-to-end. Switch off only after you've verified the connection in production. |
Step 4 — Save credentials
After creating the channel, the form gains a Credentials card.

| Credential | Notes |
|---|---|
| API Key | From the OTA's partner portal → Account → API Access. Required. Stored encrypted via libsodium AEAD (XChaCha20-Poly1305); the browser only ever sees a masked last-4 hint after save. |
| Webhook Signing Secret | Shared secret used to verify HMAC-SHA256 signatures on inbound booking webhooks. Without it, every inbound booking is rejected as unauthorized. |
After saving, click Test connection — the module hits the OTA's lightest auth probe endpoint and confirms the credential works.
Step 5 — Register the webhook URL on the OTA
The form gains an Inbound webhook URL card showing the public URL the OTA should POST to (e.g. https://yoursite.com/wp-json/yatra/v1/channel-manager/webhook/1).
- Copy the URL with the copy button.
- In the OTA's partner portal, paste it into the Booking notifications / Webhook setting.
- Save.
Click Test webhook in Yatra to verify the round-trip. The button signs a synthetic booking with your saved secret, POSTs it to your own webhook URL, and runs it through the full verification pipeline. A green toast means: signature verified, replay check passed, booking staged. A red toast tells you exactly what failed.
Firewall / VPN reachability
The webhook URL must be reachable from the public internet. If your WordPress is behind a firewall, VPN, or staging-environment IP allowlist, the OTA's webhook deliveries time out and you'll only get bookings on the next hourly cron tick.
Step 6 — Flip the channel live
Once Test connection + Test webhook both pass:
- Open the channel.
- Toggle Sandbox / test mode off.
- Toggle Enabled on.
- Save.
The channel is now live. The first push runs immediately + every subsequent trip/availability/booking change triggers an event-driven push within seconds.
Step 7 — Map your trips
Open Yatra → Channel Manager → Trip mappings → + Add mapping.

| Field | Notes |
|---|---|
| Channel | Which channel this mapping pushes to. |
| Trip ID | Numeric ID of the Yatra trip. Find it in the URL when editing the trip (?id=42). |
| Channel product ID | The product's ID on the channel side. For Viator this is a product code (e.g. 12345P1); for GetYourGuide it's the offer/option ID. Copy it from the channel's partner portal. |
| Public listing URL (optional) | Link to the channel's public listing for this product. Shown as a quick-jump link in the mappings table. |
| Per-mapping price offset (%) | Overrides the channel's default offset for this trip only. 0 inherits the channel default. |
| Sync inventory | Push seat availability to this channel. |
| Sync pricing | Push prices to this channel. Turn off when the OTA manages pricing on its side. |
One Yatra trip can map to many channels (each with its own price offset); one channel holds one mapping per Yatra trip.
Bulk operations
The mappings table supports multi-select. Tick mappings and the bulk action bar appears:
| Action | What it does |
|---|---|
| Sync selected | Pushes inventory + pricing for every selected mapping. |
| Enable | Resumes paused mappings. |
| Pause | Stops pushes without losing the configuration. |
| Delete | Removes the mappings. Existing bookings already received are unaffected. |
Capped at 200 mappings per bulk request server-side so a runaway client can't blow the PHP timeout.
Step 8 — Watch the Bookings inbox
Open Yatra → Channel Manager → Bookings inbox.

When an OTA delivers a webhook:
- Body is signed (
X-Viator-Signature/X-GYG-Signature). Receiver verifies HMAC + checks the timestamp is within ±5 minutes (replay protection). - Booking is staged — single row INSERT into the staging table. Response is sent back to the OTA inside its timeout budget.
- ~5 seconds later, a scheduled cron event promotes the staged row into a real Yatra booking. Uses a
SELECT ... FOR UPDATElock on the availability row to prevent two channels selling the last seat simultaneously.
The inbox shows three statuses:
| Status | Meaning |
|---|---|
received | Staged but not yet a real Yatra booking. Usually flips to promoted within seconds. |
promoted | Live in the standard booking list. Triggers email confirmations, payment receipts, and review-request automation just like a direct booking. The matching departure's booked_count is incremented (forced past Yatra's capacity guard, because the OTA already accepted the seat — we record what actually happened rather than refusing to acknowledge it). |
failed | Promotion threw — check the error column. Common causes: unmapped product ID, deleted trip, validation error. |
What promotion actually does
When a staged row is promoted to a Yatra booking (within ~5 seconds of the OTA webhook arriving), the following happens in order, inside a single database transaction so it's all-or-nothing:
- Customer find-or-create. The OTA guest's email is matched against your existing customers. If they've booked direct before, the new booking attaches to their existing customer record (lifetime totals stay accurate). If not, a fresh customer is created.
- Booking row inserted into the same
wp_yatra_bookingstable direct bookings use. Reference isCH-{channel_id}-{external_booking_id}so you can cross-reference back to the OTA's portal. Status isconfirmed, payment statuspaid(OTAs collect the money on their side). - Departure find-or-create + link. The matching departure is located by
(trip_id, departure_date). If none exists yet, one is created so the booking has somewhere to live. - Inventory decrement. The departure's
booked_countis incremented by the traveller count. This is forced past Yatra's normal capacity guard — if the OTA accepted a seat that Yatra thought was full, we record the booking anyway and let the operator see the oversell. Refusing to record would hide the problem.
After the transaction commits, two more things happen (outside the transaction so a slow SMTP server can't deadlock the booking row):
- Confirmation email sent to the guest using your standard booking-confirmation template (honours your brand voice, White Label settings, and email-delivery configuration).
yatra_booking_createdaction fires. Every listener that runs for direct bookings runs here too — Email Automation sequences, WhatsApp templates, Webhook subscribers, analytics modules. The OTA booking is treated as a first-class citizen of the Yatra ecosystem.
If any of the side effects (5 or 6) fails, the booking itself still succeeds — the failure is logged to Sync Activity so you can investigate without losing the row.
Booking lifecycle dispatch
Subsequent webhooks for the same external booking ID are handled by status:
| Inbound external status | Yatra action |
|---|---|
confirmed / pending | Create-or-update the Yatra booking. |
cancelled / rejected / refunded | Cancel the linked Yatra booking + fire yatra_booking_cancelled so refund automations and inventory restoration trigger as if the customer cancelled direct. |
amended / modified / updated | Patch the Yatra booking — travel_date, travelers_count, total_amount, contact details — and fire yatra_booking_modified. |
no_show | Mark the booking no-show (falls back to cancelled if your config doesn't include that status). |
Inbound webhook IP allowlist (optional)
If you want a second gate on top of the signature secret, fill the Inbound webhook IP allowlist field on the channel edit form with the OTA's documented source CIDRs. Inbound requests from any source outside the list are dropped before signature verification, so a leaked secret alone can't be exploited from an arbitrary source.
How it works:
- Paste a comma- or newline-separated list of CIDRs (IPv4 or IPv6). Empty = no restriction (default).
- The check uses the request's
REMOTE_ADDRby default. If your site sits behind a trusted proxy that forwards the real client IP viaX-Forwarded-For, tell Yatra which proxies to trust with theyatra_trusted_proxy_cidrsfilter — see the Webhooks doc for the snippet (same helper). - Rejections return HTTP 200 (same pattern as the other reject paths — non-200 would cause the OTA to retry indefinitely) and write a "IP allowlist rejected source X" row to the sync log so you can see why a delivery was dropped.
Site-wide allowlist as well: if every channel should share the same allowlist (because all OTAs deliver through the same corporate proxy), set it once via filter:
add_filter('yatra_channel_manager_webhook_ip_allowlist',
fn($cidrs, $channelId) => ['203.0.113.0/24'],
10, 2
);Per-channel and site-wide allowlists are unioned — a request passes if either list allows it.
Inbound webhook rate limit
The receiver has a built-in rate limit: 100 requests per minute per (channel, source IP). Real OTA traffic sends well under this; the cap protects against a misconfigured retry loop or an opportunistic flood. When the cap is exceeded the receiver returns HTTP 429 — legitimate OTAs back off on the Retry-After hint and try again.
Tune the cap via filter:
add_filter('yatra_channel_manager_webhook_rate_limit',
fn($limit, $channelId) => $channelId === 7 ? 500 : $limit, // higher cap for one channel
10, 2
);Reconciliation report
Open Yatra → Channel Manager → Reconciliation. The view aggregates "where do I have unfinished business?" across every channel into one read-only snapshot.
Eight KPI tiles at the top:
| Tile | What it shows |
|---|---|
| Channels enabled | Enabled / total. |
| Active mappings | Mappings currently set to sync. |
| Stale mappings | Active mappings whose last successful push is older than the staleness threshold (default 24h). |
| Open breakers | Channels where the circuit breaker is currently tripped. |
| Pending booking promotions | Inbound bookings staged but not yet promoted to real Yatra bookings. |
| Failed booking promotions (7d) | Promotions that threw an error in the last week. |
| Syncs OK (24h) / Syncs failed (24h) | Sync log success/fail counts for the last 24h. |
Below the tiles, a per-channel table flags every channel with a Needs attention badge if it has any stale mappings, pending/failed bookings, recent sync failures, or a tripped breaker. The last-failure column shows the operation, HTTP status, error message, and timestamp for the most recent failed sync — usually enough to diagnose without paging through the Sync activity log.
Customize the staleness window:
add_filter('yatra_cm_inventory_stale_seconds', fn() => 12 * 3600); // 12hThe report is computed on demand (it's a few SQL queries per channel). External monitoring can poll the REST endpoint /yatra/v1/channel-manager/reconciliation on its own cadence.
Latency report
Open Yatra → Channel Manager → Latency for sync duration percentiles. Three tables: global, per provider (channel type), and per channel. Each row shows the sample count and the average / p50 / p95 / p99 of duration_ms across two windows (24h and 7d), plus the success / fail counts.
Useful for spotting an OTA that's degraded — e.g. p95 drifting from 800 ms to 4 seconds usually means the OTA's API is under load before customers start complaining.
Percentiles are nearest-rank — simplest cross-MySQL-version-portable definition; precise enough for monitoring (not for publishing SLO numbers).
Sample pool is capped at 5,000 most-recent rows per (channel, window) so the query is fast even on a busy installation. Operators with bigger fleets can lower the cap:
add_filter('yatra_cm_latency_max_samples', fn() => 1000);Channel-credential capability
Channel credentials (API keys, webhook signing secrets) are gated by a separate, stricter capability: yatra_manage_channel_credentials. The day-to-day mapping + sync work is gated by the looser yatra_manage_channel_manager.
This means you can grant a "Channel Operator" role to a junior staff member who runs sync work, adds mappings, and investigates the sync log — without also handing them the keys to the OTA accounts. Only roles with the stricter yatra_manage_channel_credentials capability can create / edit / delete channels or set credentials.
By default the stricter capability is held only by the Owner and Manager roles. Custom roles can pick it up via the Team & Access role builder.
Health monitoring
Each channel carries a health badge in the list:
| Badge | Meaning |
|---|---|
| 🟢 Healthy | Last 10 log rows all succeeded, circuit breaker closed. |
| 🟡 Degraded | Some recent failures but recovery is still happening. |
| 🔴 Failing | Circuit breaker open, OR all recent logs failed. The badge subtitle shows the breaker state (circuit open / recovering). |
Hover the badge for a tooltip with the raw counts ("Last 10: 8 OK, 2 failed.") and the breaker's last-failure reason.
Reliability built in
The Channel Manager is designed for unattended operation — operators never have to click sync manually. Between the event-driven push and hourly cron, drift gets corrected within an hour even when something fails.
| Layer | What it does |
|---|---|
| HTTP retries | 3 attempts with exponential backoff + full jitter. 429 (with Retry-After honored) and 5xx are retried; 4xx other than 429 fails fast. |
| Idempotency-Key header | Forwarded on every write. Retries don't create duplicate resources upstream. |
| Circuit breaker | 3 consecutive failures opens the breaker for 10 minutes. While open, calls short-circuit in microseconds with a synthetic failure — no thundering herd against a dead endpoint. Half-open lets one probe through; success closes, failure re-opens. |
| Webhook signature + timestamp | HMAC-SHA256 verification with constant-time comparison + ±5 minute freshness window blocks replays of stolen payloads. |
| Two-phase booking ingestion | Stage in webhook request, promote async — webhook response is never blocked by slow Yatra-side booking creation. |
| Pessimistic lock on promotion | SELECT ... FOR UPDATE on the trip availability row prevents simultaneous overbooking across channels. |
| Sync log retention | 90 days of audit data, auto-purged. Survives module re-enables. |
REST API
| Endpoint | Verb | Purpose |
|---|---|---|
/yatra/v1/channel-manager/meta | GET | Eligibility + supported channel types + webhook URL template. |
/yatra/v1/channel-manager/channels | GET / POST | List / create channels. |
/yatra/v1/channel-manager/channels/{id} | GET / PUT / DELETE | Read / update / delete one channel. |
/yatra/v1/channel-manager/channels/{id}/credential | PUT | Set or clear one credential (api_key, webhook_secret). |
/yatra/v1/channel-manager/channels/{id}/test-connection | POST | Probe the OTA's auth endpoint. |
/yatra/v1/channel-manager/channels/{id}/test-webhook | POST | Send a signed synthetic webhook to your own receiver. |
/yatra/v1/channel-manager/channels/{id}/sync | POST | Sync every active mapping for this channel now. |
/yatra/v1/channel-manager/channels/{id}/health | GET | Health snapshot — status + breaker state + last-N log counts. |
/yatra/v1/channel-manager/mappings | GET / POST | List / create mappings. |
/yatra/v1/channel-manager/mappings/{id} | PUT / DELETE | Update / delete one mapping. |
/yatra/v1/channel-manager/mappings/{id}/sync | POST | Push this single mapping now. |
/yatra/v1/channel-manager/mappings/bulk | POST | Bulk sync / enable / disable / delete action. |
/yatra/v1/channel-manager/bookings | GET | List staged inbound bookings. |
/yatra/v1/channel-manager/logs | GET | Sync log with filters. |
/yatra/v1/channel-manager/reconciliation | GET | Reconciliation snapshot across every channel. |
/yatra/v1/channel-manager/latency | GET | Per-channel + per-provider + global latency percentiles. |
/yatra/v1/channel-manager/webhook/{channel_id} | POST | Public webhook receiver — always available even when the module is disabled, gated by signature + (optional) IP allowlist + rate limit. |
All write endpoints require manage_options + Scale-active license + module enabled. See REST API reference for the full schema.
Hooks & filters
| Hook | Purpose |
|---|---|
yatra_channel_manager_channel_types (filter) | Add or replace supported OTA adapters. Return an array of channel type definitions; each must reference a class implementing ProviderInterface. |
yatra_booking_cancelled (action) | Fires when a channel webhook cancels a Yatra booking. Listen here for refund automation. |
yatra_booking_modified (action) | Fires when a channel webhook modifies a Yatra booking. |
yatra_channel_manager_should_push (filter) | Last gate before pushing inventory or pricing to a channel — return false to skip. |
yatra_channel_manager_normalize_booking (filter) | Edit a normalized booking payload after the adapter returns it, before staging. |
yatra_module_active (action, slug=channel_manager) | Fires the moment the module is toggled on — installs the database schema. |
yatra_module_deactive (action, slug=channel_manager) | Fires when toggled off — unschedules the sync cron. Does not drop data tables. |
yatra_channel_manager_webhook_rate_limit (filter) | Override the 100-per-minute inbound webhook rate limit. Set to 0 to disable rate limiting (not recommended). |
yatra_channel_manager_webhook_ip_allowlist (filter) | Site-wide IP allowlist for inbound webhooks. Unioned with per-channel allowlists. |
yatra_trusted_proxy_cidrs (filter) | Tell the IP allowlist which proxies are trusted to forward X-Forwarded-For. |
yatra_cm_inventory_stale_seconds (filter) | Override the 24-hour staleness threshold used in the Reconciliation report. |
yatra_cm_latency_max_samples (filter) | Override the 5,000-sample cap for percentile calculation in the Latency report. |
Privacy
- Customer data flows directly between your WordPress and the OTA. No proxying through Yatra-owned infrastructure.
- Credentials are encrypted at rest with libsodium AEAD; decrypted just-in-time per request.
- Webhook bodies are logged (capped at 16 KB) for forensic review when signature verification fails. The
yatra_channel_manager_should_log_bodyfilter lets you disable that on GDPR grounds. - Sync logs purge after 90 days automatically.
Overbooking: what the module prevents, and what it can't
This is the most-asked question by operators, so it deserves an honest answer. The Channel Manager significantly reduces overbooking risk — but it does not make it physically impossible.
What the module prevents reliably:
- Two channels (e.g. Viator and your direct site) trying to confirm the last seat at the exact same instant — Yatra's last-seat lock holds the row briefly during booking promotion so only one wins.
- Inventory drifting between channels because of manual updates — Yatra pushes the new seat count to every connected OTA within ~30 seconds of any change.
- A booking that arrived on an OTA being missed if a webhook is dropped — the hourly safety-net pull re-fetches the last 24 hours of bookings on every channel.
What can still cause an overbooking, even with the module on:
- An OTA approves a booking on its side and queues the notification, but doesn't deliver it for several minutes (some OTAs batch notifications). During that gap your direct site doesn't yet know seats are sold and could confirm another booking.
- A staff member edits a seat count manually in the OTA's own dashboard, bypassing Yatra. Yatra's next push will correct it, but anything booked in the meantime is on its own.
- A booking is taken over the phone and entered late.
What we recommend:
- Keep a 1–2 seat inventory buffer on every channel mapping (set in the Pricing & inventory rules card). This is your cushion against the gap window above.
- Watch the Latency report weekly — if an OTA's p95 sync time creeps above a minute, your real-world risk window widens. We've seen this be the early warning sign before an OTA partner outage.
- For your highest-margin trips, consider listing them with a slightly reduced max seat count on OTAs vs. your direct site so the last 1–2 seats are direct-site-only.
Troubleshooting
"Channel Manager" doesn't appear in the sidebar — verify (1) your license is Scale on the License page, (2) the module is toggled on under Modules. Starter / Growth tier shows the upgrade card under Yatra → Channel Manager but no sidebar menu.
"Failed to create channel: Table doesn't exist" — this was a bug fixed in module v1.0.1. The schema is now created synchronously on module toggle-on. If you're seeing it, refresh the admin page once — the safety-net hook will install the tables.
Test connection: 401 Unauthorized — API key wrong or revoked. Re-paste from the partner portal. Check sandbox vs. production keys aren't mixed up.
Test webhook: signature_failed — Webhook Signing Secret on Yatra-side doesn't match what the OTA expects. Some OTAs let you regenerate; some pin it permanently.
Test webhook: stale_timestamp — your server clock is more than ±5 minutes off real time. Run ntpdate or check date against a public time source.
Bookings stuck in received for hours — promotion cron isn't running. Visit /wp-cron.php?doing_wp_cron once to manually flush the queue, then set up a real system cron (recommended for any production WordPress).
Pushes silently skipped (circuit_open in logs) — the OTA failed 3+ times consecutively. The breaker auto-recovers after 10 minutes; or click Test connection in the channel form which resets the breaker on a successful probe.
Customer name imports as "First Lastname-Suffix" — the OTA didn't send structured first/last fields and the fallback split used the full name string. Compound surnames ("van der Berg") are preserved — only edge cases where the OTA itself sends an unusual combined-name shape mis-parse. The customer record can be edited in Yatra → Customers after promotion.
Overbooked across two channels — should not happen with the pessimistic lock active; if it does, file a support ticket with the two booking IDs and the channel IDs so we can examine the race. As a remedy: refund one customer + reach out manually. The OTA already accepted the payment so the Yatra side is downstream of the conflict.
Useful links
- Settings → Advanced → Debug mode — captures provider request/response pairs for support tickets.
- Hooks & filters — full filter signatures + invocation order.
- REST API — endpoint schemas.
- Viator partner docs
- GetYourGuide supplier docs
Where to read more
- All modules — module catalog.
- White Label — Scale-only deeper rebrand.
- AI Assistant — Growth/Scale content generation.