> For the complete documentation index, see [llms.txt](https://resources.atriptech.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://resources.atriptech.com/api-document/product-guides/extensions-and-integrations/atlas-data-feed/flight-data-feed.md).

# Atlas Data Feed — Technical Integration Guide

This guide helps your technical team set up the reception and processing of Atlas flight pricing data.

{% hint style="info" %}
💬 **Need help?** If you're stuck, ask Eva in the Help Center for instant diagnostics.

<a href="https://www.atriptech.com/" class="button primary" data-icon="comments">Ask Eva</a>
{% endhint %}

This guide explains how to receive, process, and operate Atlas Data Feed.

For product fit, customer use cases, and the recommended booking model, see [Atlas Data Feed](/api-document/product-guides/extensions-and-integrations/atlas-data-feed.md).

### Before you begin

Use Atlas Data Feed when you need local flight data for:

* low-latency search, comparison, and ranking
* bulk pricing, analytics, or dynamic packaging
* AI retrieval over structured fare data

Data Feed is not a booking API or the final booking source of truth.

Use `getOffers.do` to retrieve the latest bookable offer after a traveller selects an itinerary. Use Atlas Transaction APIs for order creation, payment, and ticketing.

#### Use Data Feed and Transaction API together

Use Data Feed for the display stage.

Read offers from your local database.

Use `getOffers.do` at checkout to confirm the latest fare and inventory.

Recommended sequence:

1. Search local feed data.
2. Let the user select an itinerary.
3. Call `getOffers.do` to retrieve a bookable offer and `OfferId`.
4. Create the order, then pay and ticket.

{% hint style="warning" %}
Data Feed is not the final booking source of truth.

Always call `getOffers.do` before order creation and payment.
{% endhint %}

### Step 1: Prepare Your SFTP Server

Atlas delivers full and incremental files to the SFTP server provided by the customer. Please provide the following information to Atlas.

| Parameter             | Description                                  | Example                      |
| --------------------- | -------------------------------------------- | ---------------------------- |
| Server address        | SFTP hostname or IP address                  | `sftp.yourcompany.com`       |
| Port                  | SFTP port; default is 22                     | `22`                         |
| Username              | Account used by Atlas for delivery           | `atlas_push`                 |
| Authentication        | SSH public-key authentication is recommended | SSH Key                      |
| Full directory        | Destination directory for full files         | `/data/atlas/pricing/full/`  |
| Incremental directory | Destination directory for incremental files  | `/data/atlas/pricing/incre/` |

#### Authentication

SSH public-key authentication using **ed25519** (preferred) or **RSA-4096** is recommended.

* The customer installs the public key supplied by Atlas in the SFTP account's `~/.ssh/authorized_keys` file.
* Atlas securely retains the corresponding private key and uses it to connect to the customer SFTP server.
* If password authentication is temporarily used, use a password of at least 16 characters with upper-case letters, lower-case letters, numbers, and symbols; rotate it at least every 90 days. Password authentication will be deprecated in a future version; please migrate to SSH key authentication as early as possible.

A typical public-key deployment is shown below. The final allocation of key-generation, exchange, and custody responsibilities is subject to the parties' agreement.

```bash
ssh-keygen -t ed25519 -f atlas_push_ed25519 -N ""
cat atlas_push_ed25519.pub >> /home/atlas_push/.ssh/authorized_keys
chmod 600 /home/atlas_push/.ssh/authorized_keys
```

#### IP Allowlist, Directories, and Audit

* Allow only the production source IP addresses supplied by Atlas to access the SFTP port. Atlas will provide at least 14 calendar days' written notice before an IP change.
* Configure full and incremental directories separately. They may point to the same physical directory and are distinguished by file-name prefix. Both directories must exist and be writable by the push account.
* Files are written atomically: Atlas writes a temporary file first and renames it only when delivery is complete. Process only final file names and ignore temporary files.
* Size disk capacity for the agreed data scope; a large data set can be estimated at approximately 15 GB/day uncompressed (approximately 2 GB/day compressed).
* Retain SFTP login and file-operation audit logs for at least 180 days. Atlas also retains delivery logs, including time, file name, size, record count, and outcome; contact your Account Manager for an investigation.

### Step 2: Confirm Your Data Requirements

| Configuration        | Description                              | Default                |
| -------------------- | ---------------------------------------- | ---------------------- |
| Airline scope        | Comma-separated airline IATA codes       | All available airlines |
| Coverage days        | Future flight coverage                   | 360 days               |
| Compression          | `zip` or `gz`                            | `zip`                  |
| Incremental delivery | Enable or disable incremental files      | Enabled                |
| Incremental interval | Delivery frequency for incremental files | 2 minutes              |
| Integration mode     | `SHARED` or `SEPARATE`                   | `SEPARATE`             |

**Integration Modes: SHARED and SEPARATE**

| Dimension     | SHARED                                                 | SEPARATE (default)                                            |
| ------------- | ------------------------------------------------------ | ------------------------------------------------------------- |
| Scheduling    | Full and incremental delivery are serialized           | Full and incremental delivery run in parallel                 |
| Arrival order | Ordered                                                | May be out of order                                           |
| Merge rule    | Process in delivery order                              | Keep the record with the latest `update_time` for the same ID |
| Suitable for  | Incremental delay during full generation is acceptable | Most production integrations                                  |

The file format, column layout, and deletion semantics are identical in both modes; only scheduling differs. In SEPARATE mode, a newer incremental update can arrive before an older full snapshot, so merging must compare `update_time` to prevent the snapshot from overwriting newer data.

```mermaid
sequenceDiagram
    participant A as Atlas Delivery
    participant S as Customer SFTP
    Note over A,S: SHARED mode - incremental delivery waits during full generation
    A->>S: Full file generated at 10:00 and delivered at 10:15
    Note over A: Incremental changes from 10:02 to 10:14 wait in queue
    A->>S: Queued incremental file after 10:15
    Note over A,S: SEPARATE mode - deliveries run in parallel and may arrive out of order
    A->>S: Incremental file at 10:04 arrives first
    A->>S: Full snapshot generated at 10:00 arrives at 10:15
    Note over S: Compare update_time before applying the full snapshot
```

**How to Configure**

Confirm airline scope, coverage days, compression format, full and incremental directories, incremental interval, and integration mode with Atlas. Contact your Account Manager for subsequent changes and validate local scanning and merge logic after a configuration change.

### Step 3: Receive and Parse Data Files

#### File Naming Rules

The timestamp is the file generation time in UTC.

| File type   | File-name template                                                        |
| ----------- | ------------------------------------------------------------------------- |
| Full        | `atlas_yyyyMMddHHmmss.csv.zip` or `atlas_yyyyMMddHHmmss.csv.gz`           |
| Incremental | `atlas_incr_yyyyMMddHHmmss.csv.zip` or `atlas_incr_yyyyMMddHHmmss.csv.gz` |

Use the `atlas_` and `atlas_incr_` prefixes to distinguish full and incremental files.

#### Full vs. Incremental Delivery

| Dimension       | Full Delivery                                                          | Incremental Delivery                                    |
| --------------- | ---------------------------------------------------------------------- | ------------------------------------------------------- |
| Timing          | Initial integration and a default 24-hour refresh                      | Every 2 minutes by default; configurable                |
| Content         | Complete snapshot of current valid price records                       | Records changed since the prior delivery                |
| File format     | 63-column CSV; all records have `deleted=0`                            | Same 63-column CSV; may contain `deleted=1`             |
| File name       | `atlas_<timestamp>.csv.zip/.gz`                                        | `atlas_incr_<timestamp>.csv.zip/.gz`                    |
| Client handling | Rebuild/refresh the local baseline and apply the snapshot-missing rule | Merge into the local baseline by `atlas_flight_fare_id` |

Full and incremental files can use one CSV parser; only their record scope and merge semantics differ.

#### Encoding, Delimiter, and Time Zone

* Format: CSV with a header row.
* Encoding: UTF-8 without BOM.
* Delimiter and quoting: comma-separated; values containing commas or newlines are double-quoted in accordance with RFC 4180.
* `update_time`: UTC ISO 8601 in `yyyy-MM-dd'T'HH:mm:ss'Z'` format.
* Flight departure and arrival dates/times are local to the relevant airport and are not converted to UTC.

#### Decompress Files

**Zip (default):**

```bash
unzip -p atlas_20260601153045.csv.zip > data.csv
```

**Gzip:**

```bash
gunzip -c atlas_20260601153045.csv.gz > data.csv
```

#### CSV Schema v2

Full and incremental files use the **same 63-column header, column order, and data types**. Bind values by field name and validate the column count and order.

```csv
atlas_flight_fare_id,segment_1_origin_airport,segment_1_origin_terminal_airport,segment_1_date_local_takeoff,segment_1_hours_local_takeoff,segment_1_destination_airport,segment_1_destination_terminal_airport,segment_1_date_local_landing,segment_1_hours_local_landing,segment_1_via_airport,segment_1_airline,segment_1_flight_number,segment_1_aircraft_code,segment_1_cabin_class,segment_1_rbd,segment_1_operating_airline,segment_1_operating_flight_number,segment_1_fare_family,segment_2_origin_airport,segment_2_origin_terminal_airport,segment_2_date_local_takeoff,segment_2_hours_local_takeoff,segment_2_destination_airport,segment_2_destination_terminal_airport,segment_2_date_local_landing,segment_2_hours_local_landing,segment_2_via_airport,segment_2_airline,segment_2_flight_number,segment_2_aircraft_code,segment_2_cabin_class,segment_2_rbd,segment_2_operating_airline,segment_2_operating_flight_number,segment_2_fare_family,segment_3_origin_airport,segment_3_origin_terminal_airport,segment_3_date_local_takeoff,segment_3_hours_local_takeoff,segment_3_destination_airport,segment_3_destination_terminal_airport,segment_3_date_local_landing,segment_3_hours_local_landing,segment_3_via_airport,segment_3_airline,segment_3_flight_number,segment_3_aircraft_code,segment_3_cabin_class,segment_3_rbd,segment_3_operating_airline,segment_3_operating_flight_number,segment_3_fare_family,luggage_options,available_seats,currency,price,tax,transaction_fee,infant_price,infant_tax,need_apis,deleted,update_time
```

**Unique Identifier**

| Position | Field                  | Type   | Nullable | Description                                                                                                                        |
| -------- | ---------------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| 1        | `atlas_flight_fare_id` | String | No       | Unique price-record ID for inserts, updates, and deletions. Do not use flight number as the key. Allocate at least 100 characters. |

**Flight Segment Fields**

Each record contains up to three segments. Fields for a non-existent segment are blank. The same field structure is used for `segment_1_`, `segment_2_`, and `segment_3_`.

| Position (segment 1 / 2 / 3) | Field suffix                   | Format       | Nullable                     | Description                                                                                                  |
| ---------------------------- | ------------------------------ | ------------ | ---------------------------- | ------------------------------------------------------------------------------------------------------------ |
| 2 / 19 / 36                  | `origin_airport`               | String       | Blank when no segment exists | Departure airport IATA three-letter code.                                                                    |
| 3 / 20 / 37                  | `origin_terminal_airport`      | String       | Yes                          | Departure terminal.                                                                                          |
| 4 / 21 / 38                  | `date_local_takeoff`           | `yyyy-MM-dd` | Blank when no segment exists | Departure date in local airport time.                                                                        |
| 5 / 22 / 39                  | `hours_local_takeoff`          | `HH:mm`      | Blank when no segment exists | Departure time in local airport time.                                                                        |
| 6 / 23 / 40                  | `destination_airport`          | String       | Blank when no segment exists | Arrival airport IATA three-letter code.                                                                      |
| 7 / 24 / 41                  | `destination_terminal_airport` | String       | Yes                          | Arrival terminal.                                                                                            |
| 8 / 25 / 42                  | `date_local_landing`           | `yyyy-MM-dd` | Blank when no segment exists | Arrival date in local airport time.                                                                          |
| 9 / 26 / 43                  | `hours_local_landing`          | `HH:mm`      | Blank when no segment exists | Arrival time in local airport time.                                                                          |
| 10 / 27 / 44                 | `via_airport`                  | String       | Yes                          | Stopover airport for the same flight number; not the connection airport between separate itinerary segments. |
| 11 / 28 / 45                 | `airline`                      | String       | Blank when no segment exists | Marketing airline IATA code.                                                                                 |
| 12 / 29 / 46                 | `flight_number`                | String       | Blank when no segment exists | Marketing flight-number portion without airline prefix.                                                      |
| 13 / 30 / 47                 | `aircraft_code`                | String       | Yes                          | Aircraft type code.                                                                                          |
| 14 / 31 / 48                 | `cabin_class`                  | Integer      | Yes                          | `1` Economy, `2` Business, `3` First.                                                                        |
| 15 / 32 / 49                 | `rbd`                          | String       | Yes                          | Reservation Booking Designator, for example `Y`, `J`, or `C`.                                                |
| 16 / 33 / 50                 | `operating_airline`            | String       | Yes                          | Operating airline IATA code.                                                                                 |
| 17 / 34 / 51                 | `operating_flight_number`      | String       | Yes                          | Operating flight-number portion without airline prefix.                                                      |
| 18 / 35 / 52                 | `fare_family`                  | String       | Yes                          | Fare brand or product name, for example `ECO` or `FLEX`.                                                     |

**Flight Number Format**

`flight_number` and `operating_flight_number` exclude the airline prefix. Leading zeros are normalized as follows.

| Original flight number | CSV flight number |
| ---------------------- | ----------------- |
| `VZ123`                | `123`             |
| `VZ5`                  | `05`              |
| `VZ005`                | `05`              |
| `OD810`                | `810`             |

Display the complete marketing flight number as `airline + flight_number` and the complete operating flight number as `operating_airline + operating_flight_number`.

**Baggage, Availability, Price, and Status Fields**

| Position | Field             | Format         | Nullable                         | Description                                                                                                                                            |
| -------- | ----------------- | -------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 53       | `luggage_options` | String         | No                               | Adult checked baggage in `pieces-weight per piece in kg-price` format. `1-20-0` means one free 20kg checked bag. `0-0-0` means no baggage information. |
| 54       | `available_seats` | Integer        | No                               | Current sellable seat count for the complete itinerary.                                                                                                |
| 55       | `currency`        | String         | Required for active records      | ISO 4217 three-letter currency code, e.g. `CNY`, `USD`, or `THB`.                                                                                      |
| 56       | `price`           | Decimal String | May be blank for deleted records | Adult base fare excluding taxes and service fee, with two decimal places.                                                                              |
| 57       | `tax`             | Decimal String | May be blank for deleted records | Adult taxes, with two decimal places.                                                                                                                  |
| 58       | `transaction_fee` | Decimal String | May be blank for deleted records | Service fee per passenger, with two decimal places.                                                                                                    |
| 59       | `infant_price`    | Decimal String | Yes                              | Infant base fare, with two decimal places; blank when not supported.                                                                                   |
| 60       | `infant_tax`      | Decimal String | Yes                              | Infant taxes, with two decimal places; blank when not supported.                                                                                       |
| 61       | `need_apis`       | `0` / `1`      | No                               | Whether passenger travel-document/APIS information is required: `1` yes, `0` no.                                                                       |
| 62       | `deleted`         | `0` / `1`      | No                               | `0` active; `1` deleted or invalidated.                                                                                                                |
| 63       | `update_time`     | UTC ISO 8601   | No                               | Record update time, e.g. `2026-08-18T08:30:15Z`.                                                                                                       |

Adult total payable amount: `price + tax + transaction_fee`.

**Data Examples**

`_local_` date/time values are local airport time and `update_time` is UTC. Missing later segments are represented by empty fields; every production file must still contain the complete 63-column header.

**Direct itinerary:** `atlas_flight_fare_id=217159401`, `segment_1_origin_airport=DUB`, `segment_1_date_local_takeoff=2027-03-23`, `segment_1_hours_local_takeoff=19:50`, `segment_1_destination_airport=ORY`, `segment_1_date_local_landing=2027-03-23`, `segment_1_hours_local_landing=22:45`, `segment_1_airline=TO`, and `segment_1_flight_number=7909`; all segment 2 and 3 fields are empty. Baggage `1-15-40.99` means one 15kg piece priced at 40.99. With `price=39.67`, `tax=12.00`, and `transaction_fee=3.00`, the adult payable total is `54.67`.

**Two-segment itinerary:** segment 1 may be `DUS` to `AYT` (`XQ189`) and segment 2 `AYT` to `ADB` (`XQ7292`), with segment 3 empty. `1-20-0` means one free 20kg piece; `0-0-0` means no baggage data is available. Empty terminals, via airports, or fare-family values mean the source did not provide them and should be parsed as empty strings, not inferred or converted to zero.

When infant fares are supported, infant total payable amount: `infant_price + infant_tax + transaction_fee`.

#### Process Creates, Updates, and Deletes

**Full Files and Implicit Deletion**

* A full file is a complete snapshot of currently active price records.
* All records in a full file have `deleted=0`.
* Replace or rebuild the local price baseline when processing a full file.

Full files have snapshot semantics: after a full file is processed, a local record that is absent from that full file should be invalidated or removed.

In SEPARATE mode, protect newer incremental records from a late full snapshot by using the UTC timestamp in the full file name as a watermark. Remove only records whose `update_time` is earlier than that watermark and which are absent from the full file. Retain records newer than the watermark. In SHARED mode, the full snapshot can directly rebuild the local baseline.

**Incremental Files**

* An incremental file contains records changed since the preceding incremental delivery.
* `deleted=0`: insert or update the record identified by `atlas_flight_fare_id`.
* `deleted=1`: delete or invalidate the record identified by `atlas_flight_fare_id`.
* For a deleted record, `available_seats` is `0` and price fields may be blank.
* If the same ID occurs more than once, retain the record with the latest `update_time`.

**Processing Principles**

1. Use `atlas_flight_fare_id` as the sole unique key, not flight number, OD, or a segment combination.
2. A blank value means unavailable data or a non-existent segment; do not convert blank monetary values to zero automatically.
3. Use a decimal type for money; do not use floating-point arithmetic.
4. In SEPARATE mode, retain only the newest `update_time` for the same ID to protect against out-of-order delivery.
5. Full and incremental files can use the same CSV parser.

For each incremental record, look up `atlas_flight_fare_id`: insert when it does not exist and `deleted=0`; update an existing record only when the incoming `update_time` is not earlier; and delete or mark unavailable when `deleted=1`. For a full file, validate and upsert its records first, then apply the missing-record snapshot rule in section 5.1.

**Airline Onboarding and Offboarding**

* **Airline onboarding:** When an airline enters the push scope, its active records (`deleted=0`) are delivered in a subsequent incremental file. Process them as ordinary inserts or updates.
* **Airline offboarding:** When an airline stops operating or leaves the push scope, invalidated records (`deleted=1`) are delivered in a subsequent incremental file. Delete or mark them unavailable.

No additional notification interface is required; process records using `atlas_flight_fare_id` and `deleted`.

### Step 4: Test and Validate

#### End-to-End Integration Flow

```mermaid
flowchart TD
    A[Pull from SFTP] --> B[Decompress zip or gz]
    B --> C[Parse 63-column CSV]
    C --> D[Upsert by IDCompare update_timeProcess deleted flag]
    D --> E{Existing price cache or query service?}
    E -->|Yes| F1[Map fields and write to existing system]
    E -->|No| F2[Build storage model, indexes, and query service]
    F1 --> G[Business system queries flight prices]
    F2 --> G
```

#### What You Need to Check

* Connect to SFTP and read only final file names.
* Decompress zip or gzip files successfully.
* Parse UTF-8 without BOM; validate exactly 63 columns in the documented order.
* Insert, update, and delete correctly by `atlas_flight_fare_id`.
* Prevent stale data from overwriting newer data using `update_time`.
* Handle `deleted=1`, blank monetary values, and absent segments correctly.
* After a full file is processed, remove old records absent from the snapshot without deleting incremental records newer than the full-file watermark.
* Validate pushed price and tax values against Atlas search results.

#### Common Questions

| Issue                            | Likely cause                                                                | Resolution                                                                                     |
| -------------------------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| No file on SFTP                  | Incorrect directory or no write permission for the push account             | Verify the configured full/incremental directories, directory existence, and permissions.      |
| Decompression fails              | Transfer is incomplete or the file is truncated                             | Wait for the final file name; process final file names only.                                   |
| Column count mismatch            | Incorrect CSV, encoding, or field-order configuration                       | Require a header row; parse UTF-8 without BOM, comma delimiter, and the fixed 63-column order. |
| Older data overwrites newer data | Full and incremental files arrive out of order without timestamp comparison | For the same ID, retain only the record with the latest `update_time`.                         |

### Step 5: Go Live

#### Production Go-Live

After validation is complete:

1. Switch to production SFTP credentials if they differ from the test environment.
2. Confirm airline scope, directories, compression, integration mode, and delivery frequency with Atlas.
3. Receive and process the first full file to create the local price baseline.
4. Continuously process incremental files; the default delivery interval is two minutes and is configurable.
5. Create alerts for missing files, empty files, column-count errors, and parsing failures.

#### Monitoring Recommendations

* Alert when no file arrives within twice the expected interval.
* Record file name, arrival time, row count, parse successes, and parse failures for every file.
* Monitor column count, currency values, monetary formats, and duplicate-ID rate.
* Retain raw files and processing logs for at least 180 days for replay and investigation.

### Integration Effort and Timeline

#### Is This Difficult?

A standard integration has three parts:

1. Provide an accessible SFTP server.
2. Build a scheduled task to scan directories, decompress files, and parse CSV.
3. Write data to a local database, cache, or query service using the unique ID and update time.

The ingestion layer itself is straightforward: SFTP preparation is usually an operations task, and directory scanning, decompression, and CSV parsing can be implemented with standard libraries in any mainstream language. The important design points are upsert by `atlas_flight_fare_id`, ordering by `update_time`, and correct handling of full snapshots and `deleted=1` records.

| Requirement | Description                                                               | Difficulty |
| ----------- | ------------------------------------------------------------------------- | ---------- |
| SFTP server | Publicly reachable Linux server or an existing SFTP service               | Low        |
| Storage     | Space for raw and decompressed files based on airline scope and retention | Medium     |
| Scheduler   | cron or equivalent process that scans at the incremental interval         | Low        |
| Data store  | Database or cache that stores flight price records                        | Low        |

#### Indicative Timeline

The data-ingestion layer (SFTP retrieval, CSV parsing, and merge/write) typically takes 1–3 days. The time to make prices queryable also depends on whether the customer already has price storage and query capabilities.

Where a flight-data cache or query service already exists, the primary tasks are field mapping and a write adapter. A greenfield implementation additionally needs storage selection, index design, and query-service development. The ingestion workflow is the same in both cases; only the destination and query capability differ.

| Work item                                       | Scenario A: existing cache/query service | Scenario B: build from scratch      |
| ----------------------------------------------- | ---------------------------------------- | ----------------------------------- |
| Prepare SFTP server                             | 0.5 day                                  | 0.5 day                             |
| Retrieve, decompress, and parse 63-column files | 0.5 day                                  | 0.5 day                             |
| Upsert, snapshot rebuild, and deletion handling | 1 day                                    | 1 day                               |
| Storage selection and data modelling            | —                                        | 1–2 days                            |
| Data write path, indexes, and query service     | 0.5–1 day                                | 2–3 days                            |
| Validation, monitoring, and integration testing | 1–2 days                                 | 2–3 days                            |
| **Total**                                       | **approximately 4–5 person-days**        | **approximately 10–12 person-days** |

* **Scenario A:** Map fields, process files, and add a write adapter to an existing flight-data cache or query system.
* **Scenario B:** In addition to ingestion, build the data model, indexes, and query service.

#### Comparison with API Integration

|                      | File push                            | Real-time API                                                            |
| -------------------- | ------------------------------------ | ------------------------------------------------------------------------ |
| Fastest go-live      | 2–3 days                             | 1–2 weeks                                                                |
| Typical duration     | 4–5 person-days                      | 2–4 weeks                                                                |
| Technical complexity | Low: file processing and persistence | Medium to high: API orchestration, state management, and real-time calls |
