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.
Change order
Apply an OrderChange — pay a hold, add extras, or accept a reshop offer.
/v1/orders/{orderID}Requires X-API-KeyApplies a change to an order. action:
| Action | Meaning |
|---|---|
ticketing / payment / complete_payment | pay the order |
ancillaries / seats | add extras or seats |
reissue | accept a reshop offer (new flights) in offer_ids |
- No
actionis400 action_required.cancel_segmentsis400 use_cancel_confirm: cancel some flights withPOST /v1/orders/{orderID}/cancel/confirm. reissue: when the offer'stotal_amountis positive, include apaymentfor it.POST /v1/orders/{orderID}/change/confirmdoes the same with a simpler body.- Prefer
POST /v1/orders/{orderID}/servicesand/seatsfor extras. Extras here are priced from the order's seat map or service list (422 extra_not_pricedotherwise). - Paying an order already paid is
409 already_paid. A payment must be in the order's currency. On an unpaid hold pastexpires_atit is422 hold_expired. A cancelled, refunded or failed order is409 illegal_transition.
Idempotency. Idempotency-Key is required when the call pays (400 idempotency_key_required) 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 change_outcome_unknown means the answer was lost: do not resend.
Request example
curl --request PUT \
--url https://api.norba.io/v1/orders/{orderID} \
--header "X-API-Key: $NORBA_KEY" \
--header "Idempotency-Key: 3f2b8c1e-6d4a-4e9b-9a57-0c1d2e3f4a5b" \
--header "Content-Type: application/json" \
--data '{ "action": "ticketing", "payment": { "currency": "EUR", "amount": 380.62, "card": { "number": "4111111111111111", "holder": "AGENCY TRAVEL SL", "expiry_month": 11, "expiry_year": 2029 } } }'Response example
{
"order_id": "AA001Y1XD7ZA6",
"pnr": "JBQGEY",
"status": "ticketed",
"total_amount": 380.62,
"tickets": [
{
"ticket_number": "001-1234567890",
"passenger_id": "PAX96101",
"status": "issued"
}
]
}Path parameters
orderIDstringRequiredCanonical order ID.
AA001Y1XD7ZA6Query parameters
airlinestringIATA code. Optional: taken from your stored order; a different value is 400 airline does not match the order.
AARequest body
actionstringRequiredticketing, payment, complete_payment, ancillaries, seats or reissue.
ancillariesarray<Ancillary>Ancillaries to add. Prefer POST /v1/orders/{orderID}/services.
offer_idsarray<string>The reshop offers being accepted (reissue).
paymentobjectcard, amount, currency, as on POST /v1/orders. To pay the order, amount must cover the order total less your service_fee.
seatsarray<Seat>Seats to assign. Prefer POST /v1/orders/{orderID}/seats.
Error codes
400action_required, use_cancel_confirm, idempotency_key_required, payment_method_not_allowed, payment.currency must be …, the currency of this order, payment.amount is less than the airline's price for this order, airline does not match the order, or another validation message.
404order_not_found — not this account's order in this key's environment.
409illegal_transition, already_paid, order_busy, idempotency_key_in_flight, idempotency_key_reused, or an …_outcome_unknown code with attempt_id (this or an earlier payment on the order has no known outcome: do not pay again).
422hold_expired (unpaid hold past expires_at), extra_not_priced, a named refusal, or airline_refused.
502change_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.