Skip to main content

Notifications — subscribe, verify, replay

When the airline changes your order — a schedule change, a refund, a ticket issued, a passenger flown, a payment cleared — it tells you with a signed NDC notification to an HTTPS endpoint you register. You never have to poll.

What you can subscribe to​

EventMessage you receiveWhen
order.disruptedIATA_OrderChangeNotifRQa schedule change or a cancelled flight
order.changed, order.divided, order.cancelledIATA_OrderChangeNotifRQa change the airline or the customer made (never your own)
order.ticketed, order.paid, order.payment_expired, order.refundedIATA_OrderChangeNotifRQdocuments, payments and refunds
service.checked_in, service.boarded, service.flownIATA_ServiceStatusChangeNotifRQa delivery milestone of a service
service.deliveredIATA_ServiceDeliveryNotifRQservices with no ticket or EMD behind them, delivered
clearance.requested, clearance.cancelledIATA_PaymentClearanceNotifa settlement payment put up for clearance, or cancelled before it cleared
clearing.completedIATA_PaymentClearingNotifa clearing run settled your clearances

Changes you made yourself are not notified back to you — you already had the answer. The airline's own accounting feed (accounting.*) is not available to sellers.

1. Subscribe​

With a token carrying ndc:notif:subscribe (JSON, not XML):

curl -X POST https://ndc.retailaer.com/subscriptions \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"endpoint":"https://ndc.your-agency.example/notifications",
"events":["order.disrupted","order.refunded","service.flown"],
"content":"snapshot"}'
  • events — leave it out (or empty) to receive every event above.
  • content — snapshot sends the whole current order with each change; changes sends the change only.
  • The endpoint must be https, without credentials in the URL, and resolve to a public address. Redirects are not followed.

The answer carries the subscription (status: pending_verification) and its signing secret (whsec_…) — shown once. Store it like a password.

2. Verify the endpoint​

curl -X POST https://ndc.retailaer.com/subscriptions/$SUB_ID/verify \
-H "Authorization: Bearer $TOKEN"

The airline POSTs a signed JSON challenge to your endpoint:

{ "type": "ndc.subscription.challenge", "subscriptionId": "…", "challenge": "…" }

Answer 2xx with a body that contains the challenge value. The subscription turns active; nothing is delivered before that.

3. Receive — and check the signature​

Each notification is an XML POST with:

Header
IATA-Message-Namethe NDC message (table above)
X-NDC-Eventthe event, e.g. order.disrupted
X-NDC-Sequence1, 2, 3 … per subscription and order — a gap means you missed one
X-NDC-Notification-Idunique per notification — de-duplicate on it
X-NDC-Signaturet=<unix seconds>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")>

Verify the signature over the raw body, and refuse old timestamps:

import { createHmac, timingSafeEqual } from 'node:crypto';

export function verify(secret: string, header: string, rawBody: string, toleranceSec = 300): boolean {
const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header ?? '');
if (!m) return false;
const t = Number(m[1]);
if (Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
const want = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest();
const got = Buffer.from(m[2]!, 'hex');
return got.length === want.length && timingSafeEqual(got, want);
}

Answer 2xx quickly and do the work afterwards. Anything else — or no answer within 10 seconds — is a failed delivery: the airline retries with backoff (1, 5, 15, then 60 minutes) and keeps the same notification id and sequence. Deliveries are at least once; the notification id makes them exactly-once for you.

The body carries the notification's id and sequence in PayloadAttributes (CorrelationID, SeqNumber); a PaymentClearance message carries them in PayloadStandardAttributes.

4. Replay​

Missed a sequence number, or restored from a backup? Every notification is kept with the XML that was delivered:

# everything for one order after sequence 3
curl "https://ndc.retailaer.com/subscriptions/$SUB_ID/notifications?orderId=ORDER-ID&since=3" \
-H "Authorization: Bearer $TOKEN"

Each entry has the event, sequence, delivery status and the body as delivered.

Managing subscriptions​

GET /subscriptionsyour subscriptions
GET /subscriptions/{id}one
POST /subscriptions/{id}/rotatea new signing secret (shown once) — the old one stops at once
DELETE /subscriptions/{id}unsubscribe

You only ever see and manage your own subscriptions.