Quickstart
Get started with the Norba API — authenticate, search flights across all connected airlines, and create your first booking in minutes.
Norba is a production-grade NDC aggregation platform that normalizes multi-airline NDC responses into a single canonical JSON schema. Whether you're building a travel agency, an OTA, or automating corporate travel — Norba gives you one API to access every connected airline.
Base URL: https://api.norba.io/v1
No SDK Required
The Norba API is plain JSON over HTTPS — no SDK, no dependencies. Use any HTTP client in any language:
# No SDK required — use any HTTP client
# The Norba API is plain JSON over HTTPS
# Base URL: https://api.norba.io/v1Authentication
All API requests require an API key. Pass it as the X-API-Key header on every request.
Getting Your API Key
- Sign up at norba.io
- Go to Dashboard → API Keys
- Click Create API Key
- Copy the key immediately — you won't be able to see it again
Set Up the Client
curl --request GET \
--url https://api.norba.io/v1/health \
--header "X-API-Key: $NORBA_KEY"Key format: nbr_live_ prefix + 64 hex characters (74 total). Keys are stored as SHA-256 hashes — they're only shown once at creation.
Security tips: Use environment variables, create separate keys per app, and rotate periodically. You can also manage keys via the API.
Key Concepts
- Shopping — Stateless search that returns transient flight offers. Nothing is reserved until you create an order.
- Orders — Stateful bookings that persist at the airline. Includes passenger data, payment, and ticketing.
- Servicing — Post-booking operations: seat assignment, baggage, ancillaries, SSRs, APIS data.
- Aviation Data — Reference catalog: airports, airlines, aircraft types, and runway data — all accessible via the API.
Step 1: Get Your API Key
Sign up for a Norba account in under a minute. No credit card required. Your API key is available instantly from the dashboard.
Step 2: Search for Flights
Send a single JSON request and get back ranked offers from every connected airline. Filter by cabin, airline, or max stops.
curl --request POST \
--url https://api.norba.io/v1/shopping/offers \
--header "X-API-Key: $NORBA_KEY" \
--header "Content-Type: application/json" \
--data '{
"origin": "LHR",
"destination": "JFK",
"departure_date": "2026-07-15",
"adults": 1,
"max_stops": 0
}'Save the offer_id value — you'll need it for the next step.
Searching Multiple Airlines
Target specific carriers with the airlines array. Omit it to search all connected airlines simultaneously.
curl --request POST \
--url https://api.norba.io/v1/shopping/offers \
--header "X-API-Key: $NORBA_KEY" \
--header "Content-Type: application/json" \
--data '{
"origin": "LHR",
"destination": "JFK",
"departure_date": "2026-07-15",
"adults": 1,
"airlines": ["AA", "LH", "DL"]
}'Supported Airlines
Replace the airline codes with any of these:
| Airline | Code | Status |
|---|---|---|
| American Airlines | AA | Sandbox |
| Lufthansa | LH | Coming soon |
| Air France-KLM | AF | Coming soon |
| Emirates | EK | Coming soon |
| Delta Air Lines | DL | Coming soon |
| United Airlines | UA | Coming soon |
| Singapore Airlines | SQ | Coming soon |
| Qatar Airways | QR | Coming soon |
| Iberia | IB | Coming soon |
| Virgin Atlantic | VS | Coming soon |
| Qantas | QF | Coming soon |
Step 3: Price the Offer
The offer IDs from search are transient and the airline will not book them. Pricing confirms availability and mints a new, bookable offer ID — a different string from the one you searched with, and the only one POST /v1/orders accepts. Skipping this step is the single most common integration mistake — booking a shopped ID fails with 502 [230000002] Invalid or Expired Offer.
curl --request POST \
--url https://api.norba.io/v1/offers/price \
--header "X-API-Key: $NORBA_KEY" \
--header "Content-Type: application/json" \
--data '{
"offer_ids": ["AA-X2E80EC16-51FD-48AD-924B.1-1|X2E80EC16-51FD-48AD-924B.1-1-1"],
"airline": "AA"
}'The response carries the bookable offer_id and a price_guaranteed_until deadline — roughly 20 minutes. Create the order before it passes.
Step 4: Create Your First Order
Send the priced offer ID with your passengers and contact details — plus any seats and ancillaries, which must be sold in this call rather than added afterwards. You get back the canonical order with the carrier's PNR.
curl --request POST \
--url https://api.norba.io/v1/orders \
--header "X-API-Key: $NORBA_KEY" \
--header "Content-Type: application/json" \
--data '{
"offer_id": "AA-P2E80EC16-51FD-48AD-924B-1|P2E80EC16-51FD-48AD-924B-1-1",
"airline": "AA",
"passengers": [
{
"id": "T1",
"type": "ADT",
"first_name": "JOHN",
"last_name": "DOE",
"date_of_birth": "1985-04-12",
"gender": "M",
"document": {
"type": "P",
"number": "XDA123456",
"issuing_country": "GB",
"expiry_date": "2032-05-30",
"nationality": "GB"
}
}
],
"contact": { "email": "john@example.com", "phone": "447700900123" }
}'Save the order_id and the returned passenger IDs — the airline reassigns them, so the T1 you sent comes back as something like PAX96101, and every later call must use the new value.
Holds and Payment
An order is created unpaid by default — omit payment and the reservation comes back confirmed with expires_at set to the airline's payment time limit — typically a three-day hold. That is the normal agency flow.
To settle it, use POST /v1/orders/{orderID}/commit. There is no /pay endpoint. The body is snake_case like the rest of the API. If you integrated before August 2026 it was CamelCase and silently dropped snake_case keys, so ExpiryMonth needs to become expiry_month.
curl --request POST \
--url "https://api.norba.io/v1/orders/AA001Y1XD7ZA6/commit?airline=AA" \
--header "X-API-Key: $NORBA_KEY" \
--header "Content-Type: application/json" \
--data '{
"payment": {
"method": "CARD",
"currency": "EUR",
"amount": 380.62,
"card": {
"number": "4111111111111111",
"holder": "JOHN DOE",
"expiry_month": 11,
"expiry_year": 2030,
"cvv": "123",
"brand": "VISA"
}
}
}'In the sandbox the carrier accepts the card and confirms the order, but no document is issued: the order comes back confirmed with an empty tickets[] and a warning explaining why. Build your checkout to read status and tickets[] rather than the HTTP code — until tickets[] is non-empty no ticket exists, and that is exactly the check production relies on too.
What's Next?
- Airline Integrations — Supported operations, forms of payment and integration notes per airline
- Servicing guide — Add seats, bags, and ancillaries to existing orders
- Orders lifecycle — Understand the full order state machine
- Billing & payments — What Norba charges an agency for a booking, and how usage settles into an invoice
- Quality scores — Track how complete each offer's data is
- Architecture — Understand the end-to-end booking flow
- API Reference — Full endpoint reference with request/response schemas