This guide explains how to send airline booking data (Level-3 airline data) with your N-Genius online payments, and how to settle a booking in several partial captures (multi-clearing). It covers authentication, endpoints, payloads, validation rules, samples, refunds, voids and error handling.
Before you startAirline Acquiring must be enabled on your outlet. Contact your Network International relationship manager to enable it. If it isn't enabled, the gateway accepts your orders but ignores the airline data. See Errors and exceptions.
Integration overview
sequenceDiagram
participant M as Merchant server
participant N as N-Genius API
participant C as Customer
M->>N: POST /identity/auth/access-token (API key)
N-->>M: access_token
M->>N: POST /transactions/outlets/[outlet]/orders<br/>action AUTH + airlineDetails
N-->>M: 201 order (orderRef, paymentRef, payment page link)
M->>C: Redirect to payment page (or collect card via direct API)
C->>N: Enters card details
N-->>M: Payment AUTHORISED
loop For each passenger / clearing
M->>N: POST .../payments/[paymentRef]/captures<br/>amount + airline (seq, count, M/F)
N-->>M: 201 PARTIALLY_CAPTURED (or CAPTURED)
end
opt After the event
M->>N: Refund a capture / void
end
Which order action should I use?
| Action | When to use | Multi-clearing captures |
|---|---|---|
AUTH | You settle the booking in one or more captures later. Choose this for multi-passenger or multi-clearing bookings. | Yes |
PURCHASE | You charge and settle the whole amount at once. | No: the payment is captured automatically, so there is no capture step |
Airline details on the order are used for the authorisation, the sale (purchase) and every capture. You don't need to resend them for refunds, voids or reversals.
Environments and authentication
Base URLs
| Environment | Base URL |
|---|---|
| Sandbox | https://api-gateway.sandbox.ngenius-payments.com |
| Production | https://api-gateway.ngenius-payments.com |
Get an access token
Every API call needs a short-lived access token. Request one with your API key, which you can find in the N-Genius portal under Settings → Integrations → Service Accounts.
POST {baseUrl}/identity/auth/access-token| Header | Value |
|---|---|
Authorization | Basic {your_api_key} |
Content-Type | application/vnd.ni-identity.v1+json |
Accept | application/vnd.ni-identity.v1+json |
Sample request
curl --location --request POST '{baseUrl}/identity/auth/access-token' \
--header 'Authorization: Basic {your_api_key}' \
--header 'Content-Type: application/vnd.ni-identity.v1+json' \
--header 'Accept: application/vnd.ni-identity.v1+json'Sample response: 200 OK
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI...",
"expires_in": 300,
"refresh_expires_in": 1800,
"token_type": "bearer"
}-
Send the token as
Authorization: Bearer {access_token}on every transaction call. -
The token is short-lived (
expires_inis in seconds). Request a new one when it expires. -
Keep your API key and tokens on your server only. Never put them in a browser or mobile app.
Common headers
All transaction endpoints in this guide use:
| Header | Value | Required |
|---|---|---|
Authorization | Bearer {access_token} | Yes |
Content-Type | application/vnd.ni-payment.v2+json | Yes, on requests with a body |
Accept | application/vnd.ni-payment.v2+json | Yes |
API endpoints
{outletRef} is your outlet reference, which is in the N-Genius portal. {orderRef}, {paymentRef}, {captureId}, {purchaseId} and {refundId} come from earlier responses.
| # | Operation | Method | Path |
|---|---|---|---|
| 1 | Get access token | POST | /identity/auth/access-token |
| 2 | Create order (with airlineDetails) | POST | /transactions/outlets/{outletRef}/orders |
| 3 | Get order | GET | /transactions/outlets/{outletRef}/orders/{orderRef} |
| 4 | Pay with card (direct API) | PUT | /transactions/outlets/{outletRef}/orders/{orderRef}/payments/{paymentRef}/card |
| 5 | Capture (with airline) | POST | /transactions/outlets/{outletRef}/orders/{orderRef}/payments/{paymentRef}/captures |
| 6 | Get capture | GET | /transactions/outlets/{outletRef}/orders/{orderRef}/payments/{paymentRef}/captures/{captureId} |
| 7 | Void a capture | DELETE | /transactions/outlets/{outletRef}/orders/{orderRef}/payments/{paymentRef}/captures/{captureId} |
| 8 | Refund a capture | POST | /transactions/outlets/{outletRef}/orders/{orderRef}/payments/{paymentRef}/captures/{captureId}/refund |
| 9 | Refund a purchase | POST | /transactions/outlets/{outletRef}/orders/{orderRef}/payments/{paymentRef}/purchases/{purchaseId}/refund |
| 10 | Get refund | GET | /transactions/outlets/{outletRef}/orders/{orderRef}/payments/{paymentRef}/refund/{refundId} |
| 11 | Void a refund | DELETE | /transactions/outlets/{outletRef}/orders/{orderRef}/payments/{paymentRef}/refund/{refundId} |
| 12 | Void (reverse) an authorisation | PUT | /transactions/outlets/{outletRef}/orders/{orderRef}/payments/{paymentRef}/cancel |
What's new for airline: operation 2 accepts airlineDetails, and operation 5 accepts airline. All other operations are standard N-Genius operations, unchanged.
Use the response linksFollow the
_linksin each response (for examplepayment:card,cnp:capture,cnp:refund,cnp:cancel) instead of building URLs by hand where you can.
Create an order with airline details
POST {baseUrl}/transactions/outlets/{outletRef}/ordersSend the standard order fields (action, amount, and so on) plus the airlineDetails object. Every field inside airlineDetails is optional. Send what you have, and each field you send must pass its validation rule (Field reference).
Restrictions
-
Allowed only for single (one-time) orders. Recurring and subscription orders are rejected.
-
When
airlineDetailsis present, only card payment methods are offered. Alternative payment methods are hidden.
Sample request
curl --location '{baseUrl}/transactions/outlets/{outletRef}/orders' \
--header 'Authorization: Bearer {access_token}' \
--header 'Content-Type: application/vnd.ni-payment.v2+json' \
--header 'Accept: application/vnd.ni-payment.v2+json' \
--data-raw '{
"action": "AUTH",
"amount": { "currencyCode": "AED", "value": 300000 },
"language": "en",
"emailAddress": "[email protected]",
"merchantAttributes": {
"redirectUrl": "https://merchant.example.com/payment-result"
},
"airlineDetails": {
"bookingReferenceNumber": "BRN000000006",
"documentType": "PASSENGER_TICKET",
"transactionType": "TICKET_PURCHASE",
"planNumber": "01",
"itinerary": {
"numberInParty": 2,
"originCountry": "ARE",
"legs": [
{
"carrierCode": "EK",
"customerCode": "CUST12345",
"couponNumber": "1",
"departureAirport": "DXB",
"departureDate": "2026-07-15",
"departureTime": "09:30:00+04:00",
"departureTax": "15.00",
"destinationAirport": "LHR",
"destinationArrivalDate": "2026-07-15",
"destinationArrivalTime": "13:45:00+01:00",
"endorsementsRestrictions": "NONREF",
"fare": "3500.00",
"fareBasis": "JOWBH",
"fees": "120.00",
"flightNumber": "EK001",
"stopoverPermitted": false,
"taxes": "230.00",
"travelClass": "J"
}
]
},
"passengers": [
{
"title": "MR",
"firstName": "Joe",
"middleName": "Michael",
"lastName": "Bloggs",
"frequentFlyerNumber": "EK1234567890",
"specificInformation": "VIP001"
},
{
"title": "MS",
"firstName": "Jane",
"middleName": "Anne",
"lastName": "Smith",
"frequentFlyerNumber": "EK1234567891",
"specificInformation": "VIP002"
}
],
"ticket": {
"ticketNumber": "1761234567890",
"eTicket": true,
"restricted": false,
"conjunctionTicketIndicator": false,
"issue": {
"address": "Terminal 3",
"carrierCode": "EK",
"carrierName": "Emirates",
"city": "Dubai",
"country": "ARE",
"date": "2026-06-22",
"travelAgentCode": "23456789",
"travelAgentName": "Global Travel LLC"
},
"taxOrFees": [
{ "amount": "200.00", "type": "YQT" },
{ "amount": "30.00", "type": "UKS" }
],
"totalFare": "3500.00",
"totalFees": "120.00",
"totalTaxes": "230.00"
}
}
}'Sample response: 201 Created
201 CreatedThe response echoes airlineDetails. Save reference (orderRef) and _embedded.payment[0].reference (paymentRef).
{
"_id": "urn:order:2c4b0a2e-6f1d-4d8b-9b3e-0d9f1b7a6c11",
"_links": {
"self": { "href": "{baseUrl}/transactions/outlets/{outletRef}/orders/2c4b0a2e-6f1d-4d8b-9b3e-0d9f1b7a6c11" },
"payment": { "href": "https://paypage.sandbox.ngenius-payments.com/?code=8a1f3c9e2b7d4e10" }
},
"type": "SINGLE",
"action": "AUTH",
"amount": { "currencyCode": "AED", "value": 300000 },
"language": "en",
"merchantAttributes": { "redirectUrl": "https://merchant.example.com/payment-result" },
"emailAddress": "[email protected]",
"reference": "2c4b0a2e-6f1d-4d8b-9b3e-0d9f1b7a6c11",
"outletId": "{outletRef}",
"createDateTime": "2026-06-22T08:15:30.123Z",
"paymentMethods": { "card": ["VISA", "MASTERCARD"] },
"airlineDetails": { "...": "same object you sent" },
"_embedded": {
"payment": [
{
"_id": "urn:payment:7d3e5f10-2a4b-4c6d-8e9f-a1b2c3d4e5f6",
"_links": {
"self": { "href": "{baseUrl}/transactions/outlets/{outletRef}/orders/2c4b.../payments/7d3e..." },
"payment:card": { "href": "{baseUrl}/transactions/outlets/{outletRef}/orders/2c4b.../payments/7d3e.../card" }
},
"reference": "7d3e5f10-2a4b-4c6d-8e9f-a1b2c3d4e5f6",
"state": "STARTED",
"amount": { "currencyCode": "AED", "value": 300000 },
"orderReference": "2c4b0a2e-6f1d-4d8b-9b3e-0d9f1b7a6c11"
}
]
}
}
TipIf
airlineDetailsis missing from the response, Airline Acquiring isn't enabled on the outlet and the data was dropped. See Errors and exceptions.
Take the card payment
Use either option:
| Option | How | PCI scope |
|---|---|---|
| Hosted payment page (recommended) | Redirect the customer to _links.payment.href from the order response. The customer returns to your redirectUrl. | Lowest |
| Direct API | PUT the card details to _embedded.payment[0]._links["payment:card"].href | Requires PCI DSS compliance |
Direct API sample
curl --location --request PUT '{payment:card href}' \
--header 'Authorization: Bearer {access_token}' \
--header 'Content-Type: application/vnd.ni-payment.v2+json' \
--header 'Accept: application/vnd.ni-payment.v2+json' \
--data '{
"pan": "4111111111111111",
"expiry": "2030-12",
"cvv": "123",
"cardholderName": "Joe Bloggs"
}'The result is AUTHORISED (for AUTH) or PURCHASED (for PURCHASE). If the state is AWAIT_3DS, complete 3-D Secure first, as in a standard N-Genius integration. Always confirm the final state with Get order (GET .../orders/{orderRef}) before you ship the ticket.
Capture with multi-clearing data
POST {baseUrl}/transactions/outlets/{outletRef}/orders/{orderRef}/payments/{paymentRef}/capturesUse this on an AUTH order to settle the authorised amount in several partial captures, for example one capture per passenger or per ticket. Add the airline object to each capture to describe its position in the set.
Request body
| Field | Mandatory | Description |
|---|---|---|
amount.currencyCode | Yes | Same currency as the order |
amount.value | Yes | Amount for this capture, in minor units (e.g. 100000 = AED 1,000.00) |
airline.multiClrSeqNum | Yes | Position of this capture in the set, two digits: 01, 02, … |
airline.multiClrCntNum | Yes | Total number of captures in the set, two digits, e.g. 03 |
airline.multiClrInd | Yes | M = more captures will follow, F = this is the final capture |
airline.ticketNumber | Yes | Ticket number for this capture. If left out, the order's ticket number is used |
airline.passengerFirstName | Yes | Passenger first name for this capture. If left out, the first passenger on the order is used |
airline.passengerMiddleName | Yes | Passenger middle name for this capture. Same default as first name |
airline.passengerLastName | Yes | Passenger last name for this capture. Same default as first name |
Rules
-
The
airlineblock is used only for partial captures, where the capture amount is less than the amount still authorised. On a full capture it is ignored. -
Leave out optional fields you don't need. Don't send them as empty strings (
""), because the capture is rejected. -
Each optional field is applied independently. For example, you can send only
ticketNumber. -
Keep
multiClrCntNumthe same across the set, increasemultiClrSeqNumby one each time, and sendFonly on the last capture.
Sample request: capture 1 of 2 (first passenger)
curl --location '{baseUrl}/transactions/outlets/{outletRef}/orders/{orderRef}/payments/{paymentRef}/captures' \
--header 'Authorization: Bearer {access_token}' \
--header 'Content-Type: application/vnd.ni-payment.v2+json' \
--header 'Accept: application/vnd.ni-payment.v2+json' \
--data '{
"amount": { "currencyCode": "AED", "value": 150000 },
"airline": {
"multiClrSeqNum": "01",
"multiClrCntNum": "02",
"multiClrInd": "M",
"ticketNumber": "1761234567890",
"passengerFirstName": "Joe",
"passengerMiddleName": "Michael",
"passengerLastName": "Bloggs"
}
}'Sample request: capture 2 of 2 (second passenger, final)
{
"amount": { "currencyCode": "AED", "value": 150000 },
"airline": {
"multiClrSeqNum": "02",
"multiClrCntNum": "02",
"multiClrInd": "F",
"ticketNumber": "1761234567891",
"passengerFirstName": "Jane",
"passengerMiddleName": "Anne",
"passengerLastName": "Smith"
}
}Sample response: 201 Created
201 CreatedThe response is the payment. Each capture appears under _embedded["cnp:capture"]. Save the capture id from its self link if you might refund or void it.
{
"_id": "urn:payment:7d3e5f10-2a4b-4c6d-8e9f-a1b2c3d4e5f6",
"_links": {
"self": { "href": "{baseUrl}/transactions/outlets/{outletRef}/orders/2c4b.../payments/7d3e..." },
"cnp:capture": { "href": "{baseUrl}/transactions/outlets/{outletRef}/orders/2c4b.../payments/7d3e.../captures" },
"cnp:cancel": { "href": "{baseUrl}/transactions/outlets/{outletRef}/orders/2c4b.../payments/7d3e.../cancel" }
},
"reference": "7d3e5f10-2a4b-4c6d-8e9f-a1b2c3d4e5f6",
"state": "PARTIALLY_CAPTURED",
"amount": { "currencyCode": "AED", "value": 300000 },
"orderReference": "2c4b0a2e-6f1d-4d8b-9b3e-0d9f1b7a6c11",
"_embedded": {
"cnp:capture": [
{
"_links": {
"self": { "href": "{baseUrl}/transactions/outlets/{outletRef}/orders/2c4b.../payments/7d3e.../captures/5b6c7d8e-..." },
"cnp:refund": { "href": "{baseUrl}/transactions/outlets/{outletRef}/orders/2c4b.../payments/7d3e.../captures/5b6c7d8e-.../refund" }
},
"amount": { "currencyCode": "AED", "value": 150000 },
"createdTime": "2026-06-23T10:02:11.456Z",
"state": "SUCCESS"
}
]
}
}After the final capture, the payment state becomes CAPTURED once the full amount is captured. Otherwise it stays PARTIALLY_CAPTURED.
Refunds, voids and reversals
You don't send airline data on any of these operations. The gateway uses the original transaction.
| Scenario | When | Call | Body |
|---|---|---|---|
| Reverse an authorisation (release funds) | AUTH order, nothing captured yet (AUTHORISED) | PUT .../payments/{paymentRef}/cancel | none |
| Void a capture | Same day, before settlement | DELETE .../payments/{paymentRef}/captures/{captureId} | none |
| Refund a capture | After settlement, per capture (e.g. one passenger cancels) | POST .../payments/{paymentRef}/captures/{captureId}/refund | { "amount": { "currencyCode": "AED", "value": 150000 } } |
| Refund a purchase | PURCHASE order | POST .../payments/{paymentRef}/purchases/{purchaseId}/refund | { "amount": { ... } } |
| Void a refund | Before the refund settles | DELETE .../payments/{paymentRef}/refund/{refundId} | none |
-
Refunds can be partial: refund less than the capture amount, for example one fee only.
-
The total refunded can't exceed what was captured.
-
Use the
cnp:cancelandcnp:refundlinks in the responses. The gateway only returns a link when that action is currently allowed.
Sample: refund one passenger's capture
curl --location '{baseUrl}/transactions/outlets/{outletRef}/orders/{orderRef}/payments/{paymentRef}/captures/{captureId}/refund' \
--header 'Authorization: Bearer {access_token}' \
--header 'Content-Type: application/vnd.ni-payment.v2+json' \
--header 'Accept: application/vnd.ni-payment.v2+json' \
--data '{ "amount": { "currencyCode": "AED", "value": 150000 } }'The response is the payment with the refund under _embedded["cnp:refund"]. The payment state becomes PARTIALLY_REFUNDED or REFUNDED.
Sample: reverse an authorisation
curl --location --request PUT '{baseUrl}/transactions/outlets/{outletRef}/orders/{orderRef}/payments/{paymentRef}/cancel' \
--header 'Authorization: Bearer {access_token}' \
--header 'Content-Type: application/vnd.ni-payment.v2+json' \
--header 'Accept: application/vnd.ni-payment.v2+json'The payment state becomes REVERSED.
Integration flow examples
Two passengers, settled per passenger
| Step | Call | Key data | Payment state after |
|---|---|---|---|
| 1 | Get token | API key | n/a |
| 2 | Create order | action: AUTH, amount: 300000, airlineDetails with 2 passengers | STARTED |
| 3 | Customer pays | hosted page / direct card | AUTHORISED |
| 4 | Capture 1 | 150000, 01 / 02 / M, Joe Bloggs, ticket …890 | PARTIALLY_CAPTURED |
| 5 | Capture 2 | 150000, 02 / 02 / F, Jane Smith, ticket …891 | CAPTURED |
One passenger cancels after settlement
| Step | Call | Key data | Payment state after |
|---|---|---|---|
| 1–5 | As in the first example | CAPTURED | |
| 6 | Refund capture 2 | POST .../captures/{capture2Id}/refund, 150000 | PARTIALLY_REFUNDED |
Booking cancelled before any capture
| Step | Call | Key data | Payment state after |
|---|---|---|---|
| 1–3 | As in the first example | AUTHORISED | |
| 4 | Reverse authorisation | PUT .../payments/{paymentRef}/cancel | REVERSED |
Single passenger, charge immediately
| Step | Call | Key data | Payment state after |
|---|---|---|---|
| 1 | Get token | n/a | |
| 2 | Create order | action: PURCHASE, airlineDetails | STARTED |
| 3 | Customer pays | PURCHASED | |
| 4 | (Optional) refund | POST .../purchases/{purchaseId}/refund | PARTIALLY_REFUNDED / REFUNDED |
Postman collection
Two files are provided:
| File | Contents |
|---|---|
postman/Airline-Payments.postman_collection.json | All requests in this guide, in flow order, plus negative tests. Test scripts save accessToken, orderRef, paymentRef, captureId, purchaseId and refundId automatically |
postman/Airline-Payments-Sandbox.postman_environment.json | Variables: baseUrl, apiKey, outletRef (fill in apiKey and outletRef) |
How to use
-
In Postman, choose Import and import both files.
-
Select the Airline Payments – Sandbox environment, then set
apiKeyandoutletRef. -
Run 01 Get access token, then 02 Create AUTH order with airline details.
-
Open the
paymentPageUrlvariable in a browser and pay with a sandbox test card, or run 03 Pay with card (direct API) if your outlet allows it. -
Run the captures, refunds and voids in folder order.
Collection formatPostman v2.1. It can be imported by all current Postman versions.

