Travel Partner API
Sell a tour or destination operator's trips on your own website, app or booking system. You get their trips as a live feed — destinations, day-by-day itineraries, inclusions, photos, dates with seats left, the retail price and your net price — and you can book seats on your own account. Or simply frame their shop in your website: every booking through it is credited to you.
1 · Get your keys from the operator
The operator adds you as a partner, sets your commission and the trips you may sell, and sends you two keys. Or sign up yourself: apply to an operator with your Oxi account and, once it approves you, get your keys on your partner page.
- Public key (tp_pk_…) — the catalogue and availability. Safe in web pages on the websites the operator listed for you.
- Secret key (tp_sk_…) — also bookings, cancellations and your statement. Server to server only; never in a page or a URL.
Send the key as Authorization: Bearer <key>. A feed reader that cannot send headers may add the public key as ?key=. Prices are in the operator's currency. Your net price is the retail price less your commission: it is what you owe the operator for bookings on your account.
2 · The quickest way: frame the operator's shop
Your partner code (for example P1A2B3C4) is in the links the operator sends you. Every booking made through these is credited to you; the traveller pays the operator, and the operator owes you your commission.
<iframe src="https://oxishops.com/SHOP?embed=1&p=YOUR_CODE"
style="width:100%;min-height:900px;border:0" title="Trips"></iframe>
Each trip in the catalogue also carries shop_url, embed_url and, for each date, book_url and book_embed_url with your code already in them: link a single trip or a single date from an email, a WhatsApp message or your own trip page.
3 · Catalogue (public key)
GET https://oxishops.com/v1/travel/catalogue
GET https://oxishops.com/v1/travel/catalogue?since=2026-11-01T00:00:00Z trips changed since
GET https://oxishops.com/v1/travel/trips/{trip id or slug}
Answer (shortened):
{
"operator": { "name": "Sunway Tours", "currency": "NGN", "shop_url": "…", "logo_url": "…" },
"partner": { "code": "P1A2B3C4", "commission_pct": 10, "may_book": true, "own_price": true, "terms": "…" },
"generated_at": "2026-10-30T16:00:00.000Z",
"trips": [{
"id": "…", "slug": "obudu-highland-escape", "title": "Obudu Highland Escape",
"type": "nature", "type_label": "Nature and wildlife", "nights": 3, "summary": "…",
"highlights": ["…"], "included": ["Flights", "Hotel"], "not_included": ["Lunch"], "terms": "…",
"photo_url": "…", "price_from": 150000, "net_from": 135000,
"destinations": [{ "name": "Obudu Mountain Resort", "place": "Obanliku, Cross River", "things_to_do": ["…"], "photo_url": "…" }],
"itinerary": [{ "day": 1, "title": "Fly to Calabar, drive up", "stay": "Resort", "meals": "Dinner" }],
"package": {
"components": [{ "kind": "hotel", "kind_label": "Hotel / stay", "title": "3 nights, deluxe double", "provider": "Obudu Mountain Resort", "day_from": 1, "day_to": 3, "details": "…" },
{ "kind": "flight", "title": "Lagos–Calabar return, economy", "provider": "…", "day_from": 1, "day_to": 4 },
{ "kind": "tour", "title": "Cable car and canopy walk", "provider": "…", "day_from": 2 }],
"charges": [{ "id": "…", "kind": "surcharge", "label": "Peak season", "basis": "per_traveller", "amount": 20000, "optional": false },
{ "id": "…", "kind": "surcharge", "label": "Single room", "basis": "per_traveller", "amount": 45000, "optional": true },
{ "id": "…", "kind": "tax", "label": "Tourism levy", "basis": "percent", "percent": 5, "optional": false }]
},
"departures": [{
"id": "…", "starts_at": "…", "ends_at": "…", "book_by": "2026-11-29",
"seats_total": 20, "seats_left": 12, "open": true,
"prices": [{ "id": "…", "name": "Adult", "retail": 300000, "net": 270000, "left": null },
{ "id": "…", "name": "Child under 12", "retail": 150000, "net": 135000, "left": null }],
"book_url": "…?p=P1A2B3C4", "book_embed_url": "…"
}],
"shop_url": "…", "embed_url": "…", "updated_at": "…"
}]
}
Only open dates are listed. Read the catalogue as often as every few minutes; check a date's availability just before you sell it.
Packages only. A trip is sold as one package: its hotels, flights, meals, cars, experiences and tours are listed in package.components for you to show, never sold on their own. package.charges are added to the fare: surcharges (a percentage is of the fare; your commission applies to them) and taxes and levies (a percentage is of the fare and surcharges; passed on in full, no commission). Optional surcharges are chosen by their id in options when you book.
4 · Availability of one date (public key)
GET https://oxishops.com/v1/travel/departures/{departure id}
Seats left, whether it is open, and each price with its retail and net amounts. Never cached.
5 · Book on your account (secret key)
You collect from the travellers; you owe the operator the net. Send an Idempotency-Key (for example your own order number): sending the same key again returns the same booking and never books twice.
POST https://oxishops.com/v1/travel/bookings
Authorization: Bearer tp_sk_…
Idempotency-Key: SKY-48213
Content-Type: application/json
{
"departure_id": "…",
"lead": { "name": "Ngozi Okafor", "email": "ngozi@example.com", "phone": "+2348030000000", "price": "Adult" },
"travellers": [ { "name": "Emeka Okafor", "price": "Adult" }, { "name": "Ada Okafor", "price": "Child under 12" } ],
"options": ["…"],
"partner_ref": "SKY-48213",
"sell_total": 780000
}
- price is a price's id or its name, as in the catalogue.
- options (optional): the ids of optional surcharges the travellers chose, such as a single room. The other surcharges and the taxes are always added; your invoice lists them line by line.
- sell_total (optional) is what you charged the travellers. If the operator lets you set your own price it may be any amount at or above the net; otherwise it must be the retail total.
- Seats are checked and held at once; up to 50 travellers per booking.
Answer 201 (or 200 for a repeated key):
{
"ref": "TR-3F9A1C", "partner_ref": "SKY-48213", "channel": "api", "status": "confirmed",
"trip": { "slug": "obudu-highland-escape", "title": "Obudu Highland Escape" },
"departure": { "id": "…", "starts_at": "…", "meeting_point": "MMA2, Lagos" },
"travellers": [ { "name": "Ngozi Okafor", "lead": true, "price": "Adult", "pass_url": "https://oxishops.com/SHOP/pass/…" }, … ],
"currency": "NGN", "retail_total": 750000, "commission_pct": 10, "commission": 75000, "net_total": 675000, "sell_total": 780000
}
Each traveller has a pass with a QR code: send the links to your travellers, or let the operator's email reach the lead traveller. The guide checks every traveller in on the day.
6 · Look up or cancel a booking (secret key)
GET https://oxishops.com/v1/travel/bookings/{ref}
POST https://oxishops.com/v1/travel/bookings/{ref}/cancel
A booking on your account can be cancelled before the date, while nobody on it has been checked in; the seats go back on sale. Refunds to your travellers follow your own terms; between you and the operator, their terms apply.
7 · Your statement (secret key)
GET https://oxishops.com/v1/travel/statement
Every booking you made or sent, with you_owe (what is unpaid on the operator's invoices to you: the net on bookings on your account), owed_to_you (your commission on paid bookings through your link) and the balance. Each booking on your account comes with an invoice from the operator's OxiSeller shop for the net; it drops out of the totals once the operator records your payment, and your commission drops out once the operator marks it paid to you.
8 · Errors
Errors come as { "error": "…", "code": "…" } with the HTTP status:
| Status | code | Meaning |
|---|---|---|
| 401 | bad_key | Unknown or revoked key |
| 403 | partner_paused, partner_ended | The operator has paused or ended the partnership |
| 403 | needs_secret, secret_in_browser, origin | Wrong key for the call, or a website the operator has not listed |
| 403 | booking_not_allowed | You sell through your link only |
| 404 | unknown_trip, unknown_departure, unknown_booking | Not found, or not one you may sell |
| 400 | unknown_price, below_net, price_fixed | A price that does not exist; a selling price under the net, or one you may not set |
| 409 | full, closed, departed, checked_in, paid | No seats left, not open for booking, too late to cancel, or already paid toward |