---
title: "Skyscanner Flight API Integration: Developer Guide"
description: "Implement Skyscanner Flights Live Prices with x-api-key authentication, create/poll lifecycle, request-response models, itinerary/leg/segment mapping, agents, pricing options, rate limits and observability."
slug: "skyscanner-flight-api"
translationKey: "integration-skyscanner-flight-api"
locale: "en"
type: "guide"
category: "integration"
tags: ["skyscanner","flight","api","live-prices","create","poll","itinerary","agent","rate-limit"]
vertical: ["flight"]
platform: "Skyscanner"
domain: "developers.skyscanner.net"
featured: true
publishedAt: "2026-09-19"
updatedAt: "2026-09-26"
reviewedAt: "2026-09-26"
technicalVerifiedAt: "2026-09-26"
sourceVersion: "Travel APIs v3 public docs reviewed 2026-09-26"
testedAgainst: "Official public documentation; not an authorized partner account"
codeExampleStatus: "illustrative"
changelog:
  - "2026-09-26 — Provider companion standard applied; rate limits, refresh-price lifecycle, pagination and evidence boundaries clarified."
sources:
  - title: "Skyscanner — Flights Live Prices overview"
    url: "https://developers.skyscanner.net/docs/flights-live-prices/overview"
  - title: "Skyscanner — Flights Live Prices quick start"
    url: "https://developers.skyscanner.net/docs/flights-live-prices/quick-start"
  - title: "Skyscanner — Flights Live Pricing API reference"
    url: "https://developers.skyscanner.net/api/flights-live-pricing"
  - title: "Skyscanner — Authentication"
    url: "https://developers.skyscanner.net/docs/getting-started/authentication"
  - title: "Skyscanner — Flights Autosuggest"
    url: "https://developers.skyscanner.net/docs/autosuggest/flights"
  - title: "Skyscanner — Rate limits"
    url: "https://developers.skyscanner.net/docs/getting-started/rate-limits"
  - title: "Skyscanner — Refresh Prices"
    url: "https://developers.skyscanner.net/docs/flights-live-prices/refresh-prices"
---

The core architecture decision in a Skyscanner flight integration is to model **asynchronous search sessions + a canonical flight model + provider handoff**, instead of exposing upstream JSON directly to the UI.

Skyscanner's current Flights Live Prices flow uses two endpoints:

```text
POST /flights/live/search/create
        |
        v
initial / partial results
+ sessionToken
        |
        v
POST /flights/live/search/poll/{sessionToken}
        |
        v
progressively richer results
        |
        v
completed
```

This is not a classic one-request/one-response integration.

## Provider companion snapshot

| Area | Status |
|---|---|
| Access | Approved Skyscanner partnership + API key |
| Auth | Server-side `x-api-key` |
| Primary contracts | Flights Live Prices create/poll, itinerary refresh, Autosuggest |
| Data direction | Client/backend initiated create + poll |
| Pagination | Live Prices is not a paginated collection; completeness progresses through session polling |
| Polling | Core part of the contract after create |
| Public default rate limits | Flights Live Pricing Create: 100/sec and 100/min; Poll: 100/sec and 500/min. Partner agreements may differ |
| Reprice/refresh | `itineraryrefresh/create` + `itineraryrefresh/poll` refresh selected-itinerary pricing |
| Booking ownership | Downstream airline/OTA after pricing-option/deeplink handoff |
| Evidence level | Official public docs reviewed; no claim of an authorized partner-account test |
| Code examples | Illustrative |

### Capability boundary

```text
Place discovery       -> Flights Autosuggest
Initial live search   -> /flights/live/search/create
Search completion     -> /flights/live/search/poll/{sessionToken}
Selected price refresh-> /flights/live/itineraryrefresh/create
Refresh completion    -> /flights/live/itineraryrefresh/poll/{refreshSessionToken}
Booking handoff       -> pricing option / agent deep link
```

Search session, selected-itinerary refresh and downstream booking are different state machines.

### Why pagination is N/A

Flights Live Prices is not a conventional `page=2` collection. Result completeness evolves through create/poll on the same search session. Do not bolt on generic pagination; manage session progress and merge semantics instead.

### Official rate-limit defaults

Skyscanner's current public Rate Limits page lists these standard Flights defaults:

| API | Per second | Per minute |
|---|---:|---:|
| Flights Live Pricing — Create | 100 | 100 |
| Flights Live Pricing — Poll | 100 | 500 |
| Flights Indicative Prices | 100 | 500 |

Skyscanner states that limits are API-key/partner specific and can be adjusted. Runtime 429 metrics and the active partner quota therefore remain the operational source of truth.

### Price refresh / reprice lifecycle

Do not treat the first live-search pricing option as checkout truth. Skyscanner documents a selected-itinerary refresh flow:

```text
search/create
   -> search/poll
   -> user selects itinerary
   -> itineraryrefresh/create
   -> itineraryrefresh/poll
   -> refreshed pricing options
   -> agent deeplink
```

If the refresh changes price, the UI should not keep the stale search price as confirmed state. A safer internal lifecycle is:

```text
SEARCH_PRICE
REFRESHING
REFRESHED
PRICE_CHANGED
HANDOFF_READY
```



For platform responsibilities, commercial boundaries and operational decisions, see the [Skyscanner profile](/en/metasearch/flights/skyscanner). This guide covers implementation contracts and request/response handling.

## 1. Access and authentication

Access requires an approved Skyscanner partnership/API key.

Authentication:

```http
x-api-key: <your-api-key>
```

Never expose the key in browser code or public repositories.

```ts
interface SkyscannerCredentials {
  apiKeyRef: string;
}
```

Recommended boundary:

```text
Browser
  -> Your backend
      -> Skyscanner API
```

## 2. Flights Live Prices create endpoint

```http
POST https://partners.api.skyscanner.net/apiservices/v3/flights/live/search/create
Content-Type: application/json
x-api-key: <api-key>
```

Minimal request:

```json
{
  "query": {
    "market": "UK",
    "locale": "en-GB",
    "currency": "GBP",
    "queryLegs": [
      {
        "originPlaceId": { "iata": "LHR" },
        "destinationPlaceId": { "iata": "SIN" },
        "date": { "year": 2026, "month": 10, "day": 12 }
      }
    ],
    "adults": 1,
    "cabinClass": "CABIN_CLASS_ECONOMY"
  }
}
```

Required request concepts include market, locale, currency, query legs and adults. Optional fields include children ages, carrier/agent inclusion or exclusion, sustainability data, nearby airports and baggage-related options when enabled.

## 3. Internal search request

Do not make provider enums your domain contract.

```ts
interface FlightSearchRequest {
  market: string;
  locale: string;
  currency: string;

  legs: Array<{
    origin: { iata?: string; entityId?: string };
    destination: { iata?: string; entityId?: string };
    departureDate: string;
  }>;

  passengers: {
    adults: number;
    childAges: number[];
  };

  cabinClass:
    | "economy"
    | "premium_economy"
    | "business"
    | "first";
}
```

```text
Internal request
   -> Skyscanner mapper
   -> create payload
```

## 4. Handling the create response

The create call returns initial results and a `sessionToken`. Skyscanner documents the create response as a fast initial/incomplete subset used for time to first result.

Conceptual response:

```json
{
  "sessionToken": "session-token",
  "status": "RESULT_STATUS_INCOMPLETE",
  "content": {
    "results": {
      "itineraries": {
        "itinerary-1": {
          "pricingOptions": []
        }
      }
    }
  }
}
```

A successful create call does **not** mean the search is complete.

```ts
type SearchStatus =
  | "created"
  | "partial"
  | "polling"
  | "complete"
  | "failed"
  | "expired";
```

## 5. Poll endpoint

```http
POST https://partners.api.skyscanner.net/apiservices/v3/flights/live/search/poll/{sessionToken}
x-api-key: <api-key>
```

Model session state explicitly:

```ts
interface FlightSearchSession {
  id: string;
  provider: "skyscanner";
  providerSessionToken: string;
  requestHash: string;
  status: SearchStatus;
  createdAt: string;
  lastPolledAt?: string;
  completedAt?: string;
  pollCount: number;
}
```

## 6. Polling strategy

Avoid tight fixed polling loops.

Example:

```text
poll 1 -> 300 ms
poll 2 -> 500 ms
poll 3 -> 800 ms
poll 4 -> 1200 ms
poll 5+ -> 1500-2000 ms
```

Stop on completion, client disconnect, max duration, unrecoverable errors or invalid sessions.

```ts
interface PollPolicy {
  maxDurationMs: number;
  maxPollCount: number;
  initialDelayMs: number;
  maxDelayMs: number;
}
```

## 7. Progressive results

Render first useful results before the whole supplier fan-out matures.

```ts
interface FlightSearchViewState {
  status: "searching" | "partial" | "complete" | "error";
  itineraries: FlightItinerary[];
  lastUpdatedAt: string;
}
```

```text
create
  -> render first results
  -> poll
  -> merge/deduplicate
  -> rerank
  -> render
  -> poll
  -> complete
```

## 8. Canonical flight model

Keep itinerary, leg, segment, carrier, agent and pricing option separate.

```text
Itinerary
  -> Leg
      -> Segment
          -> Carrier

Itinerary
  -> PricingOption
      -> Agent
      -> DeepLink
```

```ts
interface FlightItinerary {
  id: string;
  legIds: string[];
  pricingOptions: FlightPricingOption[];
  score?: number;
}

interface FlightLeg {
  id: string;
  origin: string;
  destination: string;
  departure: string;
  arrival: string;
  durationMinutes: number;
  segmentIds: string[];
  stopCount: number;
}

interface FlightSegment {
  id: string;
  origin: string;
  destination: string;
  departure: string;
  arrival: string;
  marketingCarrierId?: string;
  operatingCarrierId?: string;
  flightNumber?: string;
}
```

## 9. Carrier and agent are different

Carriers market or operate flights. Agents sell/book itineraries.

```ts
interface FlightAgent {
  id: string;
  name: string;
  type?: "airline" | "ota";
  rating?: number;
}
```

One itinerary may be sold by several agents with different prices, fees, baggage terms or deep links.

## 10. Pricing options

```ts
interface FlightPricingOption {
  id: string;
  agentIds: string[];
  price: {
    amount: number;
    currency: string;
  };
  deepLink?: string;
  transferType?: string;
  farePolicy?: string;
}
```

```text
itinerary != offer
```

## 11. Normalize response entities

```text
Skyscanner JSON
    |
    v
Provider DTO
    |
    v
Entity dictionaries
    |
    +--> itineraries
    +--> legs
    +--> segments
    +--> carriers
    +--> agents
    |
    v
Canonical flight model
```

The frontend should consume your model, not Skyscanner DTOs.

## 12. Merge poll results

Do not blindly append every poll response.

```ts
function mergeSearchResults(
  current: FlightSearchResult,
  incoming: FlightSearchResult
): FlightSearchResult {
  // upsert by provider-stable id
  // update pricing options
  // retain newest provider state
  return current;
}
```

## 13. Autosuggest

Use Skyscanner's Flights Autosuggest for place resolution rather than guessing IATA codes from free text.

```http
POST https://partners.api.skyscanner.net/apiservices/v3/autosuggest/flights
```

```json
{
  "query": {
    "market": "UK",
    "locale": "en-GB",
    "searchTerm": "London",
    "includedEntityTypes": [
      "PLACE_TYPE_CITY",
      "PLACE_TYPE_AIRPORT"
    ]
  },
  "limit": 10,
  "isDestination": false
}
```

```ts
interface FlightPlace {
  id: string;
  entityId?: string;
  iata?: string;
  name: string;
  type: "airport" | "city" | "country";
}
```

## 14. Cache strategy

A live price cache key should include route, dates, passengers, cabin, market, locale and currency.

```text
origin
+ destination
+ dates
+ adults
+ child ages
+ cabin
+ market
+ locale
+ currency
```

Use short-lived caching for duplicate suppression and burst control, not as permanent booking truth.

## 15. Indicative vs Live

```text
Discovery
  -> indicative / aggregated data

Booking intent
  -> Flights Live Prices
```

Do not run a full live create/poll cycle for every flexible-date discovery cell.

## 16. Rate limits and 429

The API reference documents 400, 401, 403, 404, 429, 500 and 503 response classes.

For 429:

```text
backoff
+ jitter
+ quota metrics
+ duplicate suppression
+ short-lived cache
```

Potential retry candidates:

```text
429
500
503
network timeout
```

Do not blindly retry 400/401/403.

## 17. Error taxonomy

```text
SKYSCANNER_AUTH
SKYSCANNER_FORBIDDEN
SKYSCANNER_BAD_REQUEST
SKYSCANNER_RATE_LIMIT
SKYSCANNER_SESSION_INVALID
SKYSCANNER_TIMEOUT
SKYSCANNER_UPSTREAM
SKYSCANNER_PARSE
SKYSCANNER_EMPTY_RESULT
SKYSCANNER_DEEPLINK
```

## 18. Deep-link handoff

Validate the itinerary, dates, passenger context, currency, final price and mobile redirect after click.

```ts
interface FlightClickEvent {
  searchId: string;
  itineraryId: string;
  pricingOptionId: string;
  agentId: string;
  displayedPrice: number;
  currency: string;
  clickedAt: string;
}
```

## 19. Observability

Track search-session metrics:

```text
search_created
time_to_first_result
time_to_complete
poll_count
itinerary_count
agent_count
api_429
api_5xx
empty_result
deeplink_click
deeplink_failure
```

Example context:

```json
{
  "searchId": "srch_123",
  "provider": "skyscanner",
  "market": "UK",
  "currency": "GBP",
  "route": "LHR-SIN",
  "pollCount": 4,
  "providerStatus": "complete"
}
```

## 20. Example SLOs

Calibrate to your own traffic and partnership limits.

```text
create success              >= 99%
time to first useful result <= product budget
poll completion             >= 98%
429 rate                    < quota threshold
deeplink success            >= 99%
search error rate           < 1%
```

## 21. Test matrix

| Test | Expected |
|---|---|
| one-way | one leg |
| return | two legs |
| direct | zero stops |
| multi-segment | correct segment chain |
| multiple agents | one itinerary, multiple offers |
| child passenger | age context preserved |
| business cabin | correct cabin |
| different currency | correct currency |
| create partial | partial UI |
| repeated polls | no duplicate entities |
| completed | polling stops |
| 429 | backoff |
| 401 | no blind retry |
| 503 | controlled retry |
| click handoff | itinerary preserved |

## 22. Go-live checklist

- API key kept server-side
- partnership access ready
- create mapper tested
- poll orchestration tested
- session state persisted
- cancellation/timeout policy defined
- itinerary/leg/segment models separated
- carrier/agent distinction correct
- pricing options normalized
- autosuggest mapping implemented
- poll merge idempotent
- 429/backoff implemented
- observability dashboard available
- deep-link tests complete
- correlation IDs available
- client disconnect stops polling

## Summary

The correct integration boundary is:

```text
Search Request
   -> Skyscanner Adapter
   -> create
   -> partial normalize
   -> poll
   -> merge
   -> canonical itinerary
   -> pricing options
   -> agent deep link
   -> post-click quality measurement
```

Developer success means managing the asynchronous lifecycle correctly, normalizing provider-specific entities, and preserving itinerary and price context through the provider handoff.


## Idempotency and ordering

Correlate create, poll and itinerary-refresh events by provider session/token identity. Reprocessing the same poll response must not create duplicate itineraries or pricing options. Upsert incoming entities by provider-stable IDs and prevent older poll snapshots from overwriting newer refresh state.

```text
same session + same entity revision -> idempotent upsert
older snapshot                       -> ignore
newer pricing state                  -> replace/update
```
