N8Go B2B API · v1

Programmatic access to N8Go's flight inventory

Search, price and book flights from N8Go's aggregated supplier network over one REST API. Every price you receive already includes your account's own markup. You never see N8Go's underlying supplier cost. Hotels are joining the API next.

Sandbox keys are issued by N8Go directly. There's no self-serve signup yet — email partnerships@n8go.co.uk or visit b2b.n8go.co.uk.

Authentication

Every request carries your API key in the x-api-key header. There's no bearer token and no OAuth handshake. The key itself is the credential.

# n8go_sandbox_... or n8go_live_...
curl https://api.b2b.n8go.co.uk/v1/flights/search \
  -H "x-api-key: {{apiKey}}" \
  -H "content-type: application/json" \
  -d '{"origin":"LHR","destination":"JFK","departureDate":"2026-11-15","passengers":{"adults":1}}'
HeaderRequiredNotes
x-api-keyrequiredMissing or invalid keys get a 401 unauthorized. A suspended account's key is treated the same as an invalid one.
Keys are shown once, at creation. N8Go can't retrieve a lost key, only revoke it and issue a new one.

Environments & pricing

Your key is bound to exactly one environment. There's no request field to switch it. A sandbox key only ever reaches the sandbox pool, a live key only the live one.

EnvironmentKey prefixBacking inventory
Sandboxn8go_sandbox_…Fixture offers, deterministic per route and date. The same search always returns the same results.
Liven8go_live_…N8Go's real aggregated supplier pool.

Wholesale pricing

Every offer's totalPrice is computed off N8Go's own net supplier cost, then marked up by your account's own rule: a flat default percentage, or a route-specific override where one exists. This is independent of what N8Go charges its own retail customers on n8go.co.uk. An account with no rule configured is marked up 0%.

Errors

Every error response shares one shape, regardless of endpoint.

{ "code": "not_found", "message": "Flight offer not found" }
StatuscodeMeaning
400validation_failedThe request body failed schema validation. Check the accompanying issues array.
400bad_requestA business rule rejected the request (e.g. an unavailable extra id).
401unauthorizedMissing, invalid, revoked, or suspended-account key.
404not_foundThe resource, offer id, or provider namespace doesn't exist.
409price_changedThe supplier re-priced the offer before booking completed. Re-fetch rather than retry.
409offer_unavailableThe supplier withdrew the offer. Search again.
409conflictThe booking or cancellation quote is in a state that doesn't allow this action (already cancelled, quote already used or expired).
429rate_limitedToo many requests. Wait and retry.
500internal_errorSomething failed on our side. Safe to retry.
Flights
GET/v1/flights/offers/:offerId

Re-fetches one offer by its id, confirming it's still available and returning its current authoritative price.

GET /v1/flights/offers/kyte%3A7f3a...
x-api-key: {{apiKey}}

{ "offer": { /* same shape as a search result */ } }
Flights
POST/v1/flights/offers/:offerId/verify

Re-fetches the offer and, if you pass the price you were last quoted, reports whether it's changed — useful as an explicit "is this still bookable at this price" check right before checkout.

// request body (optional)
{ "expectedPrice": { "amountMinor": 24200, "currency": "GBP" } }

// response
{ "offer": { /* ... */ }, "priceChanged": false, "bookable": true }
Flights
POST/v1/flights/offers/:offerId/services

Prices ancillaries (bags, seats) against an offer before you book. Stateless: nothing is persisted until you actually create a checkout session with the same selectedExtraIds.

// request
{ "selectedExtraIds": ["ext_bag1"] }

// response
{
  "extras": [{ "id": "ext_bag1", "type": "baggage", "title": "1 checked bag, 23kg", "price": { "amountMinor": 2500, "currency": "GBP" } }],
  "updatedTotalPrice": { "amountMinor": 26700, "currency": "GBP" }
}
Flights
POST/v1/flights/price-matrix

Prices one route across a week of candidate dates around your given date, one-way or round trip — built for a fare calendar, not a single results page.

FieldTypeRequiredNotes
origin, destination, departureDate, passengersrequiredSame as search.
returnDatestringoptionalRequired if varying “return”.
varyingstringoptionaldeparture (default) or return — which date the matrix varies.
{ "matrix": [
  { "date": "2026-11-12", "totalPrice": { "amountMinor": 20400, "currency": "GBP" } },
  { "date": "2026-11-13", "totalPrice": null }
] }
totalPrice is null for a past date or a date nothing was bookable for.
Reference data
GET/v1/airlines

Also /v1/airlines/codes (just the IATA codes) and /v1/airlines/:iataCode (a single airline).

{ "airlines": [{ "iataCode": "BA", "name": "British Airways", "website": "https://www.britishairways.com" }] }
Reference data
GET/v1/airports

Add ?codes=LHR,JFK for a bulk lookup by code. /v1/airports/search?q= runs a live typeahead; /v1/airports/:iataCode fetches one.

{ "airports": [{ "iataCode": "LHR", "name": "Heathrow", "city": "London", "country": "United Kingdom" }] }
Bookings
POST/v1/checkout-sessions

Creates a pending booking and a Stripe PaymentIntent. This is where booking creation actually happens — there's no separate "create booking" call, since no money exists yet at this point. N8Go's server never touches a raw card number: your own frontend collects payment with the returned clientSecret and publishableKey, using Stripe Elements.

FieldTypeRequiredNotes
offerIdstringrequiredFrom search, get-offer, or verify.
passengersarrayrequiredFull passenger details: name, date of birth, contact, nationality.
selectedExtraIdsarrayoptionalExtra ids priced via the services endpoint.
{ "bookingId": "73e86be1-...", "clientSecret": "pi_..._secret_...", "publishableKey": "pk_..." }
Supports an Idempotency-Key header. Retrying the same request with the same key replays the original response instead of creating a second booking.
Your frontend must pass its own return_url when calling Stripe's confirmPayment() with this clientSecret — Stripe requires one whenever redirect-based payment methods are enabled, which they are by default here.
Bookings
POST/v1/bookings/:id/complete

Call this once your frontend's Stripe confirmation succeeds. N8Go verifies the payment directly against Stripe, then books and tickets the reservation with the supplier. Safe to call more than once: a booking that's already confirmed is just returned as-is.

{ "booking": {
  "id": "73e86be1-...", "status": "confirmed",
  "totalPrice": { "amountMinor": 20700, "currency": "GBP" },
  "airlineLocator": "MOCK24B09C", "offer": { /* ... */ },
  "createdAt": "2026-09-18T17:26:19.216Z", "confirmedAt": "2026-09-18T17:27:49.199Z"
} }

status is one of pending_payment, confirming, confirmed, failed, or cancelled.

Bookings
GET/v1/bookings/:id

Also GET /v1/bookings to list your bookings, newest first — supports limit (default 20, max 100) and a before cursor for pagination, returning nextCursor when there's another page.

Bookings
GET/v1/bookings/:id/services

Returns whichever extras were actually attached at checkout — a plain read of what's persisted on the booking, not a fresh supplier call.

Bookings
POST/v1/bookings/:id/cancellation-quote

Prices a cancellation before you commit to it. Returns a quoteId good for a limited time (where the supplier reports an expiry).

{ "quoteId": "35c9bd46-...", "refund": { "amountMinor": 0, "currency": "GBP" } }
POST/v1/bookings/:id/cancel

Cancels the booking. Pass a quoteId from the step above to redeem that exact quoted refund, or call it with no body to cancel directly at whatever the supplier currently offers.

{ "refund": { "amountMinor": 0, "currency": "GBP" } }

Not yet available

Built server-side but not reachable over the API yet:

CapabilityStatus
Webhooksbooking.ticketed, booking.schedule_changed, booking.cancelled — HMAC-signed delivery with retry.
Per-key rate limitingConfigurable per account; not yet enforced on /v1.
Kyte-sourced offersKyte's LCC/NDC inventory joins the live pool once N8Go completes Kyte's own supplier certification.
HotelsThe same wholesale model and sandbox-first workflow, extended to hotel inventory.

Postman collection

A collection covering every endpoint on this page: flights, reference data, and the full booking lifecycle.

https://doc.sandbox.n8go.co.uk/n8go-b2b-postman-collection.json
  1. Open Postman, click Import, choose the Link tab.
  2. Paste the URL above and import.
  3. Set the collection's apiKey variable — baseUrl is already set to https://api.b2b.n8go.co.uk.
  4. Run Search Flights, Get Offer, and the booking flow in order.