Sandbox: real offers, real PNRs, no tickets

In the sandbox these endpoints work against real carrier test inventory: a search returns real offers and you can create a real booking with a carrier PNR. Two things are worth knowing before you build against them.

  • Sandbox orders are test reservations. Nobody flies on them, and they raise no fee. Cancel what you create; anything left over expires on its own payment time limit.
  • Sandbox orders are never ticketed. A paid order comes back confirmed with an empty tickets[] and a warning saying why. Read status and tickets[], not the HTTP code — that is the check production relies on too.
Servicing

Add extras to an order

Buy bags, meals or other ancillaries against an existing booking, at the airline's price.

POST/v1/orders/{orderID}/servicesRequires X-API-Key
Adds ancillaries to an existing order. Each entry names a service_id from GET /v1/orders/{orderID}/services as ancillary_offer_id, and the passenger it is for; the price is the catalogue's, never the client's — an extra this API never showed for the order is refused with 422 extra_not_priced before the airline is called.Payment follows the booking's state. A held order simply gains the extras, settled with the fare at issuance. A ticketed order has to pay for them here, in payment, and the airline issues the EMDs in the same call. payment.amount must cover the catalogue price of what is being added (400 otherwise); anything above it is the agency's margin.The response is the updated canonical Order, persisted, with ancillaries[] as the airline now holds them; the timeline records services_added. Norba's post-sale commission applies to the increase in the airline's confirmed total. Refused 409 illegal_transition on a cancelled, refunded or failed order.

Request example

curl --request POST \
  --url https://api.norba.io/v1/orders/{orderID}/services \
  --header "X-API-Key: $NORBA_KEY" \
  --header "Content-Type: application/json" \
  --data '{ "ancillaries": [ { "ancillary_offer_id": "AA-SVC…|ITEM…", "passenger_id": "PAX96101" } ], "payment": { "method": "CARD", "currency": "EUR", "amount": 45.00, "card": { "number": "4111111111111111", "holder": "AGENCY TRAVEL SL", "expiry_month": 11, "expiry_year": 2029 } } }'

Response example

Response example
{
  "order_id": "AA001Y1XD7ZA6",
  "status": "ticketed",
  "total_amount": 425.62,
  "ancillaries": [
    {
      "ancillary_offer_id": "AA-SVC…|ITEM…",
      "type": "bag_checked",
      "name": "1st checked bag",
      "price_amount": 45,
      "currency": "EUR",
      "passenger_id": "PAX96101"
    }
  ]
}

Authorization

X-API-KeystringRequired
Opaque API key issued from the Norba dashboard. Sent on every request as the X-API-Key HTTP header. Missing or invalid keys are rejected with 401 Unauthorized.

Path parameters

orderIDstringRequired
Canonical order ID.
Example: AA001Y1XD7ZA6

Request body

ancillariesarray<object>Required
Each with ancillary_offer_id (the service_id shown), passenger_id (the order's passenger id), optional segment_ids.
paymentobject
Required on a ticketed order: method, currency, amount, card — the same shape as POST /v1/orders.

Error codes

400
ancillaries is required, a payment.card.… validation message, or payment.amount is less than the airline's price for these extras.
409
illegal_transition — the order can no longer be serviced.
422
extra_not_priced — the extra was not in the catalogue this API served for the order.
502
The airline refused the change.
503
coming_soon — order writes disabled.
POST /v1/orders/{orderID}/services — Add extras to an order