Quickstart

Get started with the Norba API — authenticate, search flights across all connected airlines, and create your first booking in minutes.

Open

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/v1

Authentication

All API requests require an API key. Pass it as the X-API-Key header on every request.

Getting Your API Key

  1. Sign up at norba.io
  2. Go to Dashboard → API Keys
  3. Click Create API Key
  4. 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:

AirlineCodeStatus
American AirlinesAASandbox
LufthansaLHComing soon
Air France-KLMAFComing soon
EmiratesEKComing soon
Delta Air LinesDLComing soon
United AirlinesUAComing soon
Singapore AirlinesSQComing soon
Qatar AirwaysQRComing soon
IberiaIBComing soon
Virgin AtlanticVSComing soon
QantasQFComing 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
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
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"
      }
    }
  }'
Sandbox payments never issue a ticket

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?

Norba API Docs — Flight Search & Booking in One REST API