Sandbox keys reach the airlines’ test systems: nobody flies on these orders and no booking fee is charged. Check status and tickets[], not the HTTP code.
Add extras to an order
Buy bags, meals or other ancillaries against an existing booking, at the airline's price.
/v1/orders/{orderID}/servicesRequires X-API-KeyAdds extras to an order. Each entry names a service_id from GET /v1/orders/{orderID}/services as ancillary_offer_id, and the passenger. The price is the catalogue's; an extra not listed there is 422 extra_not_priced.
- On an unpaid hold, the extras are added and paid with the fare.
- On a ticketed order, send a
paymentcovering the extras, in the order's currency. - A cancelled, refunded or failed order is
409 illegal_transition.
Returns the updated Order. Idempotency. Idempotency-Key is required when a payment is sent (400 idempotency_key_required without it) and works as on POST /v1/orders. Another write still running on the order is 409 order_busy (Retry-After: 5). A refusal from the airline is 422; 503 airline_unreachable means nothing was sent (retry with the same key); 502 extras_outcome_unknown means the answer was lost: do not resend.
Request example
curl --request POST \
--url https://api.norba.io/v1/orders/{orderID}/services \
--header "X-API-Key: $NORBA_KEY" \
--header "Idempotency-Key: 3f2b8c1e-6d4a-4e9b-9a57-0c1d2e3f4a5b" \
--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
{
"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"
}
]
}Path parameters
orderIDstringRequiredCanonical order ID.
AA001Y1XD7ZA6Request body
ancillariesarray<object>RequiredEach with ancillary_offer_id (the service_id shown), passenger_id (the order's passenger id), optional segment_ids.
paymentobjectRequired on a ticketed order: card, amount, currency, as on POST /v1/orders.
Error codes
400idempotency_key_required, payment_method_not_allowed, ancillaries is required, payment.amount is less than the airline's price for these extras, payment.currency must be …, the currency of this order, or another validation message.
404order_not_found — not this account's order in this key's environment.
409illegal_transition, order_busy, idempotency_key_in_flight, idempotency_key_reused, or extras_outcome_unknown (with attempt_id: do not buy again).
422extra_not_priced, hold_expired, or airline_refused.
502extras_outcome_unknown with attempt_id: the answer was lost. Do not resend.
503airline_unreachable or ledger_unavailable (Retry-After: 5, nothing was sent), or coming_soon.