Lydira API
TR

Import guides

Tickets

Push ticket sales from your own system, or send the GDS ticketing-printer file.

A ticket sale is one booking with a shared itinerary and one ticket per passenger, each passenger carrying their own cost and sell lines.

On this page

A key with one of these scopes reaches it:importimport_issue

Ticketstickets

POST/api/v1/imports/tickets

Create-once: re-sending the same external_id skips rather than duplicating.

Endpoints

  • validatePOST /api/v1/imports/tickets/validate
  • importPOST /api/v1/imports/tickets
  • feedGET /api/v1/imports/tickets/records
  • read_backGET /api/v1/imports/tickets/records/{external_id}

A new row must carry

passengerspnr (unless option_date)

Sample request billed by its bill-to (no customer key)

curl -X POST 'https://YOUR-CELL.lydira.com/api/v1/imports/tickets/validate' \
  -H 'Authorization: Bearer sek_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 8f14e45f-ea2c-4f33-9a3b-6d0c1b7e5a90' \
  -d '{
  "source_system": "crm",
  "rows": [
    {
      "external_id": "TICKET-1001-B",
      "pnr": "ABC123",
      "gds_pnr": "ABC123",
      "currency": "EUR",
      "settlement_channel": "bsp",
      "fare_type": "normal",
      "miles_used": 2,
      "reservation_giver_name": "Ada Lovelace",
      "issuing_system": "amadeus",
      "corporate_code": "TKCORP2026",
      "booked_at": "2026-03-14T09:30:00+03:00",
      "tags": [
        "corporate"
      ],
      "transaction_date": "2026-03-14",
      "invoice_date": "2026-03-18",
      "notes": "Imported from the source system.",
      "legs": [
        {
          "airline_code": "TK",
          "flight_number": "1985",
          "departure_airport": "IST",
          "arrival_airport": "FCO",
          "departure_at": "2026-03-14T09:30:00+03:00",
          "arrival_at": "2026-03-14T12:45:00+03:00",
          "cabin_class": "economy",
          "booking_class": "L",
          "fare_basis": "LLXOW",
          "baggage_allowance": "1PC",
          "operating_carrier": "TK",
          "fare_family": "EcoFly",
          "refundable": true,
          "changeable": true,
          "change_fee": "1250.00",
          "refund_fee": "1250.00",
          "status": "confirmed"
        }
      ],
      "passengers": [
        {
          "first_name": "Ada",
          "last_name": "Lovelace",
          "nationality": "TR",
          "national_id": "10000000146",
          "passport_number": "U01234567",
          "passport_country": "TR",
          "passport_expiry": "2031-06-30",
          "date_of_birth": "1988-04-21",
          "gender": "MRS",
          "frequent_flyer_number": "TK123456789",
          "name": "Ada Lovelace",
          "type": "adult",
          "ticket_number": "235-1234567890",
          "cost_lines": [
            {
              "kind": "base_fare",
              "amount": "1250.00",
              "label": "Imported line",
              "currency": "EUR",
              "vat_rate": "20",
              "tax_inclusive": true
            }
          ],
          "sell_lines": [
            {
              "kind": "package_price",
              "amount": "1250.00",
              "label": "Imported line",
              "currency": "EUR",
              "vat_rate": "20",
              "tax_inclusive": true,
              "customer_visible": true
            }
          ]
        }
      ],
      "supplier_external_id": "SUPPLIER-1001",
      "bill_to_legal_name": "Lovelace Seyahat A.Ş.",
      "bill_to_tax_number": "1234567890",
      "bill_to_tax_office": "Beşiktaş",
      "bill_to_address_line": "Nispetiye Cad. No:12",
      "bill_to_city": "İstanbul",
      "bill_to_country": "TR"
    }
  ]
}'
Fields(47)
  • external_idstring

    source primary key → ExternalReference

  • pnrstring

    required unless the sale is still on option (option_date set)

  • gds_pnrstring
  • currencycurrency
  • settlement_channelenum

    who we pay — drives the airline payable + BSP recon

    One of:bspdirectwebcardconsolidatorprepaid

  • fare_typetaxonomy

    taxonomy fare_type (normal, award, …)

    Your account's fare_type list; it starts with:normalawardstafftour_conductor

  • miles_usedinteger
  • reservation_giver_namestring
  • issuing_systemstring
  • corporate_codestring

    the airline corporate code the booking was made under (as entered in the GDS); never filled from the customer by the API

  • option_datestring

    ticketing deadline: the agency's wall clock (YYYY-MM-DDTHH:MM), an ISO-8601 instant (read on that clock), or a date alone for the end of that day; set ⇒ the sale opens as option rather than draft, unless every passenger carries a ticket number: then it is dropped (option_dropped warning)

  • booked_atdatetime

    when the reservation was made (an instant, ISO-8601 with offset)

  • cost_center_codestring

    a department of the sale's (corporate) customer, by its code

  • line_template_idstring

    an invoice line template; see reference_options.line_templates

  • reservation_agent_emailemail

    the agency user who took the booking; defaults to the key's user

  • issuing_agent_emailemail

    the agency user who issued it; defaults to the reservation agent

  • card_account_idstring

    the company card that paid; required when settlement_channel is card. See reference_options.card_accounts

  • cost_fx_ratedecimal

    this sale's own purchase rate

  • sell_fx_ratedecimal

    this sale's own selling rate

  • tagsstring[]

    tag names, applied to every ticket

  • commission_partner_idstring

    the introducer who brought the sale; see reference_options.commission_partners

  • introducer_commission_typeenum

    One of:flatpercentage

  • introducer_commission_valuedecimal
  • issueboolean

    issue the invoice after saving (the key needs the import_issue scope)

  • issue_optionsobject

    the invoice's issue options, as the Issue invoice dialog takes them; every key is optional and a blank one keeps the account's default

    Keys

    • serial_prefixstring

      the invoice series to number it in

    • einvoice_scenarioenum

      Türkiye e-Fatura profile

      One of:temelticariihracatkamu

    • line_template_idstring

      see reference_options.line_templates

    • e_invoice_design_idstring

      the e-invoice design (XSLT) to print with

    • footer_notestring
    • notesstring
    • order_referencestring

      the buyer's PO number

    • issued_ondate
    • due_ondate

      not before issued_on

    • internet_saleboolean
    • transmit_nowboolean

      send the e-invoice at once; default false

    • currencycurrency

      the currency the document is cut in; blank keeps the sale's

    • settlement_modeenum

      what the invoice is settled from; blank lets the customer's rule decide

      One of:on_accountwalletcreditwallet_credit

    • settlement_partialboolean

      settle partly when the balance falls short; blank follows the customer's rule

    • print_traveler_namesboolean

      default true

    • merge_identical_linesboolean

      default false

    • consolidate_linesboolean

      one line per VAT rate; default false

    • consolidated_default_descriptionstring
    • consolidated_descriptionsobject

      the text of each consolidated line, by VAT rate ({"20": "Air travel"})

    • bill_to_namestring

      overrides the buyer's name on this invoice

    • bill_to_tax_numberstring
    • bill_to_addressstring
    • bill_to_emailemail
    • gib_aliasstring

      the buyer's e-Fatura mailbox alias

    • withholding_codesobject

      VAT withholding code by product type (transfer, tour, meal, event, hotel, cruise, rental, charter, visa, package); "" for none

    • internet_sale_detailsobject

      internet_web_address, internet_payment_method, internet_payment_date, internet_carrier_name, internet_carrier_tax_id, internet_dispatch_date

  • transaction_datedate

    işlem tarihi — the FX anchor for every cost line

  • invoice_datedate
  • notesstring
  • custom_fieldsobject

    the account's own fields on the sale, by key; see custom_fields in GET /api/v1/imports/entities/tickets

  • legsobject[]

    shared itinerary; int/dom + one-way/round-trip are derived from the airports

    Each item

    • airline_codestring
    • flight_numberstring
    • departure_airportstring
    • arrival_airportstring
    • departure_atdatetime
    • arrival_atdatetime
    • cabin_classstring

      Values the app uses:economypremium_economybusinessfirst

    • booking_classstring
    • fare_basisstring
    • baggage_allowancestring
    • operating_carrierstring

      the airline that flies it, when not the marketing carrier

    • fare_familystring

      branded fare / fare package name

    • refundableboolean

      omit when unknown

    • changeableboolean

      omit when unknown

    • change_feemoney

      the airline's change penalty, in the sale's currency

    • refund_feemoney

      the airline's refund penalty, in the sale's currency

    • statusenum

      One of:confirmedcancelledwaitlistpending

  • passengersobject[]requiredPII

    one Ticket each; identities are auto-saved to the customer's traveller directory

    Each item

    • first_namestringPII
    • last_namestringPII
    • nationalitystring
    • national_idstringPII
    • passport_numberstringPII
    • passport_countrystring
    • passport_expirydate
    • date_of_birthdatePII
    • genderstring

      Values the app uses:MRMRSMISSMSTR

    • frequent_flyer_numberstring
    • namestringPII

      full name; or send first_name + last_name

    • typestring

      taxonomy passenger_type (adult, child, infant)

      Your account's passenger_type list; it starts with:adultchildinfantstudentseniormilitaryseamandiplomat

    • ticket_numberstring
    • custom_fieldsobject

      the account's own fields on the passenger, by key

    • idstring

      amendments only: the passenger's id from the read-back. Keys the item leaves out keep their stored value; an item without an id is a new passenger

    • cost_center_codestring

      overrides the sale's department

    • complimentaryboolean

      bedelsiz hizmet; the key's role needs complimentary__grant

    • complimentary_reasonstring

      Your account's complimentary_reason list; it starts with:marketing_promoloyaltyservice_recoveryfam_trippartner_courtesystaff_travelother

    • complimentary_coverageenum

      One of:fullfare_only

    • service_fee_waivedboolean

      true: the account's service-fee rules write no fee on this passenger

    • cost_linesobject[]

      cost-side pricing lines for the "flight" pricing context

      Each item

      • kindstringrequired

        Values the app uses:base_fareairline_taxesyq_fuel_surchargegds_feeseat_selectionbaggage_feemeal_upgradeancillary_bundlelounge_accesschange_feecommissionservice_feesupplier_refundinsurance_premium

      • amountmoneyrequired
      • labelstring
      • currencycurrency
      • vat_ratedecimal

        percent (20 ⇒ 20% KDV); omit to take the kind's default

      • tax_inclusiveboolean

        true ⇒ the amount includes VAT. A hotel stay or a charter takes one VAT mode: the lines' flags decide it, lines stating both are refused, and every line follows the booking's mode afterwards

      • tax_codestring

        IATA tax code (TR, YQ, XT…) for an airline_taxes line

      • document_numberstring

        an ancillary EMD's document number

    • sell_linesobject[]

      sell-side pricing lines for the "flight" pricing context

      Each item

      • kindstringrequired

        Values the app uses:package_pricemarkupservice_feesupplier_commissioncancellation_feeinsurance_premiumdiscountrefund_allowancebase_fareairline_taxesyq_fuel_surchargegds_feeseat_selectionbaggage_feemeal_upgradeancillary_bundlelounge_accesschange_feecommissionsupplier_refund

      • amountmoneyrequired
      • labelstring
      • currencycurrency
      • vat_ratedecimal

        percent (20 ⇒ 20% KDV); omit to take the kind's default

      • tax_inclusiveboolean

        true ⇒ the amount includes VAT. A hotel stay or a charter takes one VAT mode: the lines' flags decide it, lines stating both are refused, and every line follows the booking's mode afterwards

      • tax_codestring

        IATA tax code (TR, YQ, XT…) for an airline_taxes line

      • document_numberstring

        an ancillary EMD's document number

      • customer_visibleboolean

        false folds the line into the fare on the invoice; a markup line defaults to false

      • exemption_codestring

        GİB VAT exemption code override

      • markup_percentdecimal

        the percentage this markup was entered as

      • discount_percentdecimal

        the percentage this discount was entered as

      • markup_amountmoney

        an ancillary EMD's markup share of amount

      • discount_amountmoney

        an ancillary EMD's discount share of amount

  • customer_external_idreference
  • supplier_external_idreference

    the settlement supplier (airline / consolidator) we pay

  • bill_to_typeenum

    omit to infer: a legal name or a 10-digit tax number ⇒ corporate

    One of:corporateindividual

  • bill_to_legal_namestring
  • bill_to_tax_numbertax_numberPII

    VKN for a corporate payer, TCKN for an individual; matched digits-only

  • bill_to_tax_officestring
  • bill_to_passport_numberstringPII

    individual only; used when there is no TCKN

  • bill_to_first_namestringPII
  • bill_to_last_namestringPII
  • bill_to_emailemailPII

    stored on a NEW cari; never used to match

  • bill_to_phonephonePII

    stored on a NEW cari; never used to match

  • bill_to_address_linestringPII
  • bill_to_districtstringPII
  • bill_to_citystringPII
  • bill_to_zipstringPII
  • bill_to_countrystring

    ISO-2 code, e.g. TR

References

  • customer_external_id → customers · matched by external_id, email · when missing skip
  • supplier_external_id → suppliers · matched by external_id, code · when missing skip

Your account's own fields (custom_fields)

Each agency adds its own fields in Settings → Custom fields: a project code, a trip reason, an employee number. They differ from account to account, so this page cannot list them. Your integration asks the API for them.

GET /api/v1/imports/entities/{key} answers, under custom_fields, the fields your key's account has on this entity: record for the record itself, traveler for each traveller. Each one names its key (what the row sends), its type, whether it is required, which customers it applies_to and, for a choice, its options. Read it when you build the mapping and again when the agency says it changed a field: it is the account's live list.

Request · the account's fields

curl -X GET 'https://YOUR-CELL.lydira.com/api/v1/imports/entities/tickets' \
  -H 'Authorization: Bearer sek_YOUR_API_KEY'
Response · custom_fields (excerpt)
200
{
  "key": "tickets",
  "custom_fields": {
    "record": [
      {
        "key": "project_code",
        "label": "Project code",
        "type": "text",
        "required": "always",
        "applies_to": "all"
      },
      {
        "key": "trip_reason",
        "label": "Trip reason",
        "type": "select",
        "required": "listed_customers",
        "applies_to": "listed_customers",
        "options": [
          {
            "value": "meeting",
            "label": "Meeting"
          },
          {
            "value": "fair",
            "label": "Trade fair"
          }
        ],
        "customers": [
          {
            "id": "9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18",
            "external_id": "CUST-17",
            "required": true
          }
        ]
      }
    ],
    "traveler": [
      {
        "key": "employee_no",
        "label": "Employee no",
        "type": "text",
        "required": "never",
        "applies_to": "all",
        "pii": true
      }
    ]
  }
}

What each type takes

typevalue in the row
text"PRJ-2026-001"
long_text"Fair delegation, second group"
number12.5
date"2026-03-14"
booleantrue
select"meeting"
multi_select["meeting", "fair"]

number takes a number or a numeric string; date an ISO date; select one option value (or its label); multi_select a list of them.

required and applies_to

  • requiredneveralwayslisted_customers

    listed_customers: required only for the customers marked required in customers.

  • applies_toalllisted_customers

    listed_customers: the field is accepted only on those customers' records.

Send the values as one JSON object by key. An unknown key, a value of the wrong type or a missing required field fails the row and names the key. On an amendment (on_conflict: update) the object merges by key: a key you leave out is kept, a key sent as null is removed. A field the agency prints on the customer's documents cannot change once the record is invoiced.

Traveller fields go on each traveller, under that item's own custom_fields.

They come back the same way: under detail.custom_fields in the read-back and the webhook body (and on each passenger of a ticket). A field marked personal comes back only to a key whose role can read personal data, and never in a webhook.

Reading it back

Once the agency works the record (confirms it, numbers the tickets, invoices it) this is what GET /api/v1/imports/{entity}/records/{external_id} answers, and what every webhook delivers. detail carries what only the agency can add after your push.

GET /api/v1/imports/tickets/records/TICKET-1001
200
{
  "entity": "tickets",
  "external_id": "TICKET-1001",
  "source_system": "crm",
  "type": "TicketSale",
  "id": "9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18",
  "created_at": "2026-03-14T09:30:00Z",
  "updated_at": "2026-03-15T11:05:00Z",
  "status": "issued",
  "locked": true,
  "lock_reason": "invoiced",
  "currency": "EUR",
  "invoices": [
    {
      "id": "4b8e1f60-7c2d-4e9a-b3f5-0a6d2c9e8b71",
      "number": "LYD2026000000117",
      "status": "issued",
      "currency": "EUR",
      "total": "1250.0",
      "balance": "1250.0"
    }
  ],
  "detail": {
    "pnr": "ABC123",
    "gds_pnr": "ABC123",
    "settlement_channel": "bsp",
    "corporate_code": "TKCORP2026",
    "custom_fields": {
      "project_code": "PRJ-2026-001",
      "trip_reason": "meeting"
    },
    "passengers": [
      {
        "id": "9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18",
        "name": "Ada Lovelace",
        "type": "adult",
        "ticket_number": "235-1234567890",
        "status": "issued",
        "custom_fields": {
          "employee_no": "E-10442"
        }
      },
      {
        "id": "4b8e1f60-7c2d-4e9a-b3f5-0a6d2c9e8b71",
        "name": "Byron Lovelace",
        "type": "child",
        "ticket_number": "235-1234567891",
        "status": "issued",
        "custom_fields": {
          "employee_no": "E-10442"
        }
      }
    ],
    "legs": [
      {
        "flight": "TK1985",
        "from": "IST",
        "to": "FCO",
        "departure_at": "2026-03-14T06:30:00Z",
        "arrival_at": "2026-03-14T09:45:00Z",
        "cabin_class": "economy",
        "booking_class": "L",
        "fare_basis": "LLXOW",
        "baggage_allowance": "1PC",
        "fare_family": "EcoFly",
        "refundable": true,
        "changeable": true,
        "change_fee": "1250.0",
        "refund_fee": "1250.0",
        "status": "confirmed"
      }
    ]
  }
}

Request · dry run, every field

curl -X POST 'https://YOUR-CELL.lydira.com/api/v1/imports/tickets/validate' \
  -H 'Authorization: Bearer sek_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 8f14e45f-ea2c-4f33-9a3b-6d0c1b7e5a90' \
  -d '{
  "source_system": "crm",
  "rows": [
    {
      "external_id": "TICKET-1001",
      "pnr": "ABC123",
      "gds_pnr": "ABC123",
      "currency": "EUR",
      "settlement_channel": "bsp",
      "fare_type": "normal",
      "miles_used": 2,
      "reservation_giver_name": "Ada Lovelace",
      "issuing_system": "amadeus",
      "corporate_code": "TKCORP2026",
      "booked_at": "2026-03-14T09:30:00+03:00",
      "cost_center_code": "SALES-IST",
      "line_template_id": "9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18",
      "reservation_agent_email": "booking@agency.example",
      "issuing_agent_email": "ticketing@agency.example",
      "card_account_id": "9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18",
      "cost_fx_rate": "36.2150",
      "sell_fx_rate": "36.5000",
      "tags": [
        "corporate"
      ],
      "commission_partner_id": "9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18",
      "introducer_commission_type": "percentage",
      "introducer_commission_value": "2.5",
      "issue": true,
      "issue_options": {
        "serial_prefix": "LYD",
        "einvoice_scenario": "temel",
        "line_template_id": "9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18",
        "e_invoice_design_id": "9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18",
        "footer_note": "Thank you for flying with us.",
        "notes": "Group booking, March fair.",
        "order_reference": "PO-2026-0117",
        "issued_on": "2026-03-14",
        "due_on": "2026-03-18",
        "internet_sale": false,
        "transmit_now": false,
        "currency": "EUR",
        "settlement_mode": "on_account",
        "settlement_partial": false,
        "print_traveler_names": true,
        "merge_identical_lines": true,
        "consolidate_lines": false,
        "consolidated_default_description": "Air travel",
        "consolidated_descriptions": {
          "20": "Air travel"
        },
        "bill_to_name": "Lovelace Seyahat A.Ş.",
        "bill_to_address": "Nispetiye Cad. No:12, Beşiktaş, İstanbul",
        "gib_alias": "urn:mail:defaultpk@lovelace.example",
        "withholding_codes": {
          "transfer": ""
        },
        "internet_sale_details": {
          "internet_web_address": "https://agency.example",
          "internet_payment_method": "KREDIKARTI/BANKAKARTI",
          "internet_payment_date": "2026-03-14"
        }
      },
      "transaction_date": "2026-03-14",
      "invoice_date": "2026-03-18",
      "notes": "Imported from the source system.",
      "custom_fields": {
        "project_code": "PRJ-2026-001",
        "trip_reason": "meeting"
      },
      "legs": [
        {
          "airline_code": "TK",
          "flight_number": "1985",
          "departure_airport": "IST",
          "arrival_airport": "FCO",
          "departure_at": "2026-03-14T09:30:00+03:00",
          "arrival_at": "2026-03-14T12:45:00+03:00",
          "cabin_class": "economy",
          "booking_class": "L",
          "fare_basis": "LLXOW",
          "baggage_allowance": "1PC",
          "operating_carrier": "TK",
          "fare_family": "EcoFly",
          "refundable": true,
          "changeable": true,
          "change_fee": "1250.00",
          "refund_fee": "1250.00",
          "status": "confirmed"
        }
      ],
      "passengers": [
        {
          "first_name": "Ada",
          "last_name": "Lovelace",
          "nationality": "TR",
          "national_id": "10000000146",
          "passport_number": "U01234567",
          "passport_country": "TR",
          "passport_expiry": "2031-06-30",
          "date_of_birth": "1988-04-21",
          "gender": "MRS",
          "frequent_flyer_number": "TK123456789",
          "name": "Ada Lovelace",
          "type": "adult",
          "ticket_number": "235-1234567890",
          "custom_fields": {
            "employee_no": "E-10442"
          },
          "cost_center_code": "SALES-IST",
          "service_fee_waived": true,
          "cost_lines": [
            {
              "kind": "base_fare",
              "amount": "1000.00",
              "label": "Base fare",
              "currency": "EUR",
              "vat_rate": "0",
              "tax_inclusive": true
            },
            {
              "kind": "airline_taxes",
              "amount": "150.00",
              "label": "Airline taxes",
              "currency": "EUR",
              "vat_rate": "0",
              "tax_inclusive": true,
              "tax_code": "TR"
            },
            {
              "kind": "seat_selection",
              "amount": "25.00",
              "label": "Seat selection",
              "currency": "EUR",
              "vat_rate": "0",
              "tax_inclusive": true,
              "document_number": "235-9876543210"
            }
          ],
          "sell_lines": [
            {
              "kind": "base_fare",
              "amount": "1000.00",
              "label": "Base fare",
              "currency": "EUR",
              "vat_rate": "0",
              "tax_inclusive": true,
              "customer_visible": true,
              "exemption_code": "351"
            },
            {
              "kind": "airline_taxes",
              "amount": "150.00",
              "label": "Airline taxes",
              "currency": "EUR",
              "vat_rate": "0",
              "tax_inclusive": true,
              "customer_visible": true,
              "tax_code": "TR"
            },
            {
              "kind": "markup",
              "amount": "115.00",
              "label": "Markup",
              "currency": "EUR",
              "vat_rate": "0",
              "tax_inclusive": true,
              "customer_visible": false,
              "markup_percent": "10"
            },
            {
              "kind": "discount",
              "amount": "-57.50",
              "label": "Discount",
              "currency": "EUR",
              "vat_rate": "0",
              "tax_inclusive": true,
              "customer_visible": true,
              "discount_percent": "5"
            },
            {
              "kind": "seat_selection",
              "amount": "35.00",
              "label": "Seat selection",
              "currency": "EUR",
              "vat_rate": "0",
              "tax_inclusive": true,
              "customer_visible": true,
              "document_number": "235-9876543210",
              "markup_amount": "10.00",
              "discount_amount": "0.00"
            }
          ]
        },
        {
          "first_name": "Byron",
          "last_name": "Lovelace",
          "nationality": "TR",
          "passport_country": "TR",
          "passport_expiry": "2031-06-30",
          "date_of_birth": "2018-09-02",
          "gender": "MSTR",
          "name": "Byron Lovelace",
          "type": "child",
          "ticket_number": "235-1234567891",
          "custom_fields": {
            "employee_no": "E-10442"
          },
          "cost_center_code": "SALES-IST",
          "service_fee_waived": true,
          "cost_lines": [
            {
              "kind": "base_fare",
              "amount": "1000.00",
              "label": "Base fare",
              "currency": "EUR",
              "vat_rate": "0",
              "tax_inclusive": true
            },
            {
              "kind": "airline_taxes",
              "amount": "150.00",
              "label": "Airline taxes",
              "currency": "EUR",
              "vat_rate": "0",
              "tax_inclusive": true,
              "tax_code": "TR"
            }
          ],
          "sell_lines": [
            {
              "kind": "base_fare",
              "amount": "1000.00",
              "label": "Base fare",
              "currency": "EUR",
              "vat_rate": "0",
              "tax_inclusive": true,
              "customer_visible": true,
              "exemption_code": "351"
            },
            {
              "kind": "airline_taxes",
              "amount": "150.00",
              "label": "Airline taxes",
              "currency": "EUR",
              "vat_rate": "0",
              "tax_inclusive": true,
              "customer_visible": true,
              "tax_code": "TR"
            }
          ],
          "complimentary": true,
          "complimentary_reason": "loyalty",
          "complimentary_coverage": "fare_only"
        }
      ],
      "customer_external_id": "CUSTOMER-1001",
      "supplier_external_id": "SUPPLIER-1001"
    }
  ]
}'

Every field the entity takes. Ids name your account's own records (cards, partners, templates): read them from reference_options on GET /api/v1/imports/entities/{key}, as you read the custom_fields keys there.

Response
200
{
  "import": {
    "id": "9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18",
    "entity": "tickets",
    "source_system": "crm",
    "status": "ready",
    "company_id": "9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18",
    "stats": {
      "total": 1,
      "will_create": 1,
      "will_update": 0,
      "created": 0,
      "updated": 0,
      "skipped": 0,
      "invalid": 0,
      "failed": 0,
      "not_selected": 0
    },
    "error": null,
    "created_at": "2026-03-14T09:30:00Z",
    "links": {
      "self": "/api/v1/imports/9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18",
      "rows": "/api/v1/imports/9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18/rows"
    },
    "mode": "validate",
    "async": false,
    "on_conflict": "skip",
    "pricing": "apply_rules"
  },
  "ignored_fields": [],
  "results": [
    {
      "row": 1,
      "external_id": "TICKET-1001",
      "status": "will_create",
      "payer": {
        "outcome": "external_id",
        "customer_id": "9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18"
      }
    }
  ]
}

The flow

  1. Dry-run. POST …/validate runs the same path and writes nothing.
  2. Send. The same body without /validate. A bad row fails alone and names its field.
  3. Read back. GET /api/v1/imports/{entity}/records/{external_id} answers with your own key.
  4. Listen. Webhooks tell you when the agency changes the record.

Conventions →Webhooks →

From a GDS printer file (Air Printer)

Recent captures

GET/api/v1/ticket_imports

Reachable with a narrow key: ticket_import

Newest first. Doubles as the agent's "test connection" probe and its "last N imported" panel; walk page.next_cursor to read back past the first page, which is what a reconnecting agent needs after an outage.

Parameters

Query

  • limitintegerdefault 25

    Rows per page.

  • cursorstring

    Opaque; take it from the previous response's page.next_cursor.

Response · 200

  • dataobject[]required
    Show fields
    • iduuid
    • statusenum

      one ofparsedduplicatefailed

    • providerstring
    • formatstring
    • filenamestringnullable
    • ticket_sale_iduuidnullable
    • errorstringnullable
    • captured_atdate-timenullable
    • created_atdate-time
    • duplicate_ticket_numbersstring[]nullable

      On a ticket-grain duplicate, the document numbers this capture repeats.

  • pageobjectrequired

    The cursor for the list beside it. Re-send the same request with ?cursor=<next_cursor> while has_more is true. next_cursor is null on the last page.

    Show fields
    • next_cursorstringrequirednullable
    • has_morebooleanrequired
    • limitintegerrequired

Responses

  • 401Missing or invalid Bearer token
  • 403The key lacks the required scope, or the plan doesn't include API access
  • 429Rate limit exceeded
curl -X GET 'https://YOUR-CELL.lydira.com/api/v1/ticket_imports' \
  -H 'Authorization: Bearer sek_YOUR_API_KEY'
Response
200
{
  "data": [
    {
      "id": "9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18",
      "status": "parsed",
      "provider": "amadeus",
      "format": "amadeus_air",
      "filename": "AIR07.05.24.1342.0000.txt",
      "ticket_sale_id": "9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18",
      "error": null,
      "captured_at": "2026-03-14T09:30:00Z",
      "created_at": "2026-03-14T09:30:00Z",
      "duplicate_ticket_numbers": null
    }
  ],
  "page": {
    "next_cursor": "MjAyNi0wMy0xNFQwOTozMDowMC4wMDAwMDBafDk0MQ",
    "has_more": true,
    "limit": 25
  }
}

Submit a printer file

POST/api/v1/ticket_imports

Reachable with a narrow key: ticket_import

201 when the file parsed into a new draft sale, 200 when it was already captured (same bytes, or a ticket number the account holds) and 422 when it could not be parsed — the capture is still recorded, so a failure is visible rather than lost.

The GDS and the format are sniffed from the CONTENT and are authoritative over any provider / format the agent sends.

Parameters

Headers

  • Idempotency-Keystring

    Your own unique string for this write (a UUID is the obvious choice), max 255 characters. Optional: omit it and nothing changes. Send it and a repeat of the same request returns this call's response verbatim, with Idempotent-Replay: true, instead of writing again.

Body

  • contentstringrequired

    The printer file, base64-encoded.

  • filenamestring
  • encodingstring

    Source encoding, when it is not UTF-8.

  • providerstring

    A hint only; the content decides.

  • formatstring

    A hint only; the content decides.

  • agentobject

    The desktop agent's own build, for support.

    Show fields
    • versionstring
    • hoststring
    • osstring

Response · 200

  • iduuid
  • statusenum

    one ofduplicate

  • providerstring
  • formatstring
  • filenamestringnullable
  • ticket_sale_iduuidnullable
  • errorstringnullable
  • captured_atdate-timenullable
  • created_atdate-time
  • duplicate_ticket_numbersstring[]nullable

Responses

  • 201Parsed into a new draft ticket sale
  • 401Missing or invalid Bearer token
  • 403The key lacks the required scope, or the plan doesn't include API access
  • 422The file could not be parsed; the capture is recorded anyway
  • 429Rate limit exceeded
curl -X POST 'https://YOUR-CELL.lydira.com/api/v1/ticket_imports' \
  -H 'Authorization: Bearer sek_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 8f14e45f-ea2c-4f33-9a3b-6d0c1b7e5a90' \
  -d '{
  "content": "QUlSLUJMSzIwNzs3QTs7MjQ3OzAwMDAwMDAwMDA7MUExNDUwMTk3OzAwMTAwMQ0KQU1EIDA3MDAwMTI3NTM7MS8xOw0K",
  "filename": "AIR07.05.24.1342.0000.txt",
  "encoding": "Windows-1254",
  "provider": "amadeus",
  "format": "amadeus_air"
}'
Response
200
{
  "id": "9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18",
  "status": "duplicate",
  "provider": "amadeus",
  "format": "amadeus_air",
  "filename": "AIR07.05.24.1342.0000.txt",
  "ticket_sale_id": "9d2f7c3a-1b4e-4a7d-8e51-2c0f6b9a4d18",
  "error": null,
  "captured_at": "2026-03-14T09:30:00Z",
  "created_at": "2026-03-14T09:30:00Z",
  "duplicate_ticket_numbers": [
    "235-1234567890"
  ]
}