Sterling

Developers

Sterling Travel & Tour — Partner API

Search, hold, add travellers, pay from your wallet and follow your bookings from your own systems.

Book flights for your customers from your own systems. Create a key on Organisation → API keys (shown once), send it as X-API-Key. Money is always integer minor units. Writes need Idempotency-Key. Each key has its own requests-per-minute limit (X-RateLimit-Limit / X-RateLimit-Remaining). Flow: search → hold an offer → upload each traveller's passport image (trips abroad) → add the travellers → pay from your organisation's wallet → poll the order until TICKETED.

Version 1.0.0 · openapi.json

curl -X POST {API}/v1/flights/search \
  -H "X-API-Key: stt_live_…" -H "content-type: application/json" \
  -d '{"slices":[{"origin":"ADD","destination":"NBO","date":"2026-12-01"}],"passengers":{"adults":1}}'

FlightsSearch

post/v1/flights/searchSearch flights

Offers at your sell price, by currency then cheapest first (up to 200). A trip that starts outside Ethiopia is answered in two currencies: Ethiopian Airlines in ETB, the other airlines in USD — currencies lists them and each offer's price.currency says which. A company with a travel policy sees travelPolicy on each offer.

Request body (example)

{
  "slices": [
    {
      "origin": "ADD",
      "destination": "NBO",
      "date": "2026-12-01"
    }
  ],
  "passengers": {
    "adults": 0,
    "children": 0,
    "infants": 0
  },
  "cabin": "ECONOMY"
}

Responses

  • 200 Offers
  • 400 Invalid search.
  • 401 Missing, invalid, revoked or expired API key (`api_key_required` / `api_key_invalid`).
  • 403 The key's owner may not do this.
  • 429 Too many requests for this key — wait `Retry-After` seconds (`RATE_LIMITED`).

OrdersHold, travellers, pay, status

post/v1/ordersHold an offer

Locks the price for a short time (holdExpiresAt). Refused with 409 when the flight leaves too soon, the offer is gone or your travel policy blocks it (travel_policy).

Parameters

  • Idempotency-Key header · requiredA unique value per operation (8–128 characters). A retry with the same key and body returns the first answer.

Request body (example)

{
  "offerId": "string",
  "search": {
    "slices": [
      {
        "origin": "ADD",
        "destination": "NBO",
        "date": "2026-12-01"
      }
    ],
    "passengers": {
      "adults": 0,
      "children": 0,
      "infants": 0
    },
    "cabin": "ECONOMY"
  }
}

Responses

  • 201 The held order
  • 401 Missing, invalid, revoked or expired API key (`api_key_required` / `api_key_invalid`).
  • 403 The key's owner may not do this.
  • 409 Cannot be held.
  • 429 Too many requests for this key — wait `Retry-After` seconds (`RATE_LIMITED`).
get/v1/orders/{id}Get an order

Poll after paying until status is TICKETED (tickets in fulfilment.tickets).

Parameters

  • id path · required

Responses

  • 200 The order
  • 401 Missing, invalid, revoked or expired API key (`api_key_required` / `api_key_invalid`).
  • 403 The key's owner may not do this.
  • 404 Not found.
  • 429 Too many requests for this key — wait `Retry-After` seconds (`RATE_LIMITED`).
put/v1/orders/{id}/passengersAdd the travellers

The airline's booking rules are checked here; a refused traveller answers 409 with the reasons. The booking contact must give a phone number (contact.phone); every traveller gives a middle name and every adult a mobile number (passengers.N.phone). A birth date is required for every traveller, except an adult on a domestic trip (every airport in Ethiopia). On a trip abroad the typed passport number and expiry date must match the uploaded passport image: otherwise 422 document_image_mismatch with the fields in details.fieldErrors (passengers.N.document.number / passengers.N.document.expiresOn).

Parameters

  • id path · required

Request body (example)

{
  "passengers": [
    {
      "type": "ADT",
      "givenName": "string",
      "middleName": "string",
      "surname": "string",
      "gender": "MALE",
      "birthDate": "2026-12-01",
      "email": "string",
      "phone": "+251911000000",
      "document": {
        "type": "PASSPORT",
        "number": "string",
        "issuingCountry": "ET",
        "nationality": "ET",
        "expiresOn": "2026-12-01",
        "imageFileId": "00000000-0000-4000-8000-000000000000"
      },
      "infantOfPosition": 0
    }
  ],
  "contact": {
    "email": "string",
    "phone": "+251911000000",
    "refused": false
  }
}

Responses

  • 200 Saved
  • 400 Invalid travellers: e.g. no contact phone, or a missing birth date (`details.fieldErrors`).
  • 401 Missing, invalid, revoked or expired API key (`api_key_required` / `api_key_invalid`).
  • 403 The key's owner may not do this.
  • 409 Refused by the booking rules.
  • 422 Passport image problems: `document_image_required`, `document_image_invalid`, `document_image_not_passport`, `document_image_mismatch` (`details.reason`, `details.fieldErrors`).
  • 429 Too many requests for this key — wait `Retry-After` seconds (`RATE_LIMITED`).
post/v1/orders/{id}/passengers/document-imageUpload a traveller's passport image

A trip abroad needs an image of every traveller's passport (PDF, JPEG or PNG, 8 MB max). Send the answer's imageFileId as document.imageFileId when adding the travellers; without one, a trip abroad is refused (422 document_image_required). For a trip abroad the image is read on upload: only a passport data page is accepted (a national ID or any other picture answers 422 document_image_not_passport; an illegible page 422 document_image_unreadable — upload a clearer photo). The number and expiry date read from it must match what you send with the travellers.

Parameters

  • id path · required

Responses

  • 201 Stored
  • 401 Missing, invalid, revoked or expired API key (`api_key_required` / `api_key_invalid`).
  • 403 The key's owner may not do this.
  • 404 Not found.
  • 422 No file, an unsupported type, or too large; on a trip abroad also `document_image_not_passport` or `document_image_unreadable` (`details.reason`).
  • 429 Too many requests for this key — wait `Retry-After` seconds (`RATE_LIMITED`).
post/v1/orders/{id}/payPay from your organisation's wallet

Captures the amount due from the wallet in currency (409 insufficient_funds when short). Booking and ticketing then run in the background — poll the order.

Parameters

  • id path · required
  • Idempotency-Key header · requiredA unique value per operation (8–128 characters). A retry with the same key and body returns the first answer.

Request body (example)

{
  "currency": "ETB"
}

Responses

  • 201 The payment
  • 401 Missing, invalid, revoked or expired API key (`api_key_required` / `api_key_invalid`).
  • 403 The key's owner may not do this.
  • 409 Cannot be paid.
  • 429 Too many requests for this key — wait `Retry-After` seconds (`RATE_LIMITED`).

AccountBookings and wallet

get/v1/bookingsYour organisation's bookings

Parameters

  • page query

Responses

  • 200 A page of bookings
  • 401 Missing, invalid, revoked or expired API key (`api_key_required` / `api_key_invalid`).
  • 403 The key's owner may not do this.
  • 429 Too many requests for this key — wait `Retry-After` seconds (`RATE_LIMITED`).
get/v1/walletYour organisation's wallet balances

Responses

  • 200 Wallets per currency
  • 401 Missing, invalid, revoked or expired API key (`api_key_required` / `api_key_invalid`).
  • 403 The key's owner may not do this.
  • 429 Too many requests for this key — wait `Retry-After` seconds (`RATE_LIMITED`).