Skip to content
FX-Port/Docs
GuidesAPI referenceChangelog
Get API keys
  • Introduction
  • Quickstart
  • Security
  • Authentication
  • Environments and Postman
  • Sandbox
  • Conventions and naming
  • Legacy names and twins
  • Errors
  • Rate limits and fair use
  • Streaming search results

Account and suppliers

  • Suppliers
  • Overview
  • List balances
  • Balance history
  • Booking history
  • Booking detail
  • Use these docs with AI

Account · Account and suppliers

Booking history

Booking summaries across all products, newest first.

GET/api/v1/history

GET /api/v1/history

Permission: Read

Booking summaries across one or all products (flights, hotels, eSIMs and transfers), newest first, limited to the environment of your key. eSIM orders and topups are listed (type tells them apart).

The records are lightweight: enough for status tracking, reconciliation and dashboards. For one booking in full, use the booking detail (GET /api/v1/bookings/{booking_id}) or the product's own endpoint (for example POST /api/v1/flights/get_booking).

Query parameters

ParameterTypeDefaultDescription
productstringallall, flights, hotels, esims or transfers. Case does not matter and the singular names (flight, hotel, esim, transfer) are read as the plural. Anything else is 400 invalid_product
statusstringnoneKeep bookings with exactly this status, for example confirmed. Case does not matter; spaces and hyphens are read as underscores (On Hold is on_hold); letters, digits and _, at most 32 characters. pending is accepted as another name of awaiting_payment. A status nothing has returns an empty list
date_fromstringnoneInclusive start, on the creation time of the booking. Any ISO 8601 spelling is read: a date (2026-07-01 or 20260701, 00:00:00 UTC) or a datetime with 1 to 9 fraction digits and an offset written Z, +01:00 or +0100 (in a URL write the + as %2B). Without an offset a datetime is UTC
date_tostringnoneInclusive end, in the same spellings. A bare date means the end of that day (23:59:59.999999 UTC). Not before date_from
pageinteger1The page, starting at 1 (at most 10,000). An empty value means not sent
limitinteger20Entries per page, 1 to 100 (not 200). A larger value is refused with 422 validation_error; an empty value means not sent

Legacy names (still work; the response carries a deprecated_field warning; date_from and date_to win when both are sent):

LegacyUse instead
from, from_datedate_from
to, to_datedate_to

Never send agency_id: an API key that does is refused with 400 agency_id_not_allowed.

Pagination

pagination is { page, limit, total, total_pages, hasMore, has_more }. total is the real number of bookings that match (all products together). The pages are served from the 200 newest bookings of each product, so with product=all at most 800 bookings can be reached by paging: follow has_more (hasMore is the same value), and use date_from and date_to to read an older period.

Request examples

# The latest eSIM bookings
curl --get \
  --url https://api.fx-port.com/api/v1/history \
  --header 'Authorization: Bearer fxp_test_YOUR_KEY' \
  --data-urlencode 'product=esims' \
  --data-urlencode 'limit=2'

# Confirmed flights of a period
curl --get \
  --url https://api.fx-port.com/api/v1/history \
  --header 'Authorization: Bearer fxp_test_YOUR_KEY' \
  --data-urlencode 'product=flights' \
  --data-urlencode 'status=confirmed' \
  --data-urlencode 'date_from=2026-11-01' \
  --data-urlencode 'date_to=2026-11-30'
const params = new URLSearchParams({ product: "flights", status: "confirmed", date_from: "2026-11-01", limit: "100" });
const response = await fetch(`https://api.fx-port.com/api/v1/history?${params}`, {
  headers: { Authorization: "Bearer fxp_test_YOUR_KEY" },
});
const { data: bookings, pagination } = await response.json();
// keep the internal id as your key; bookingId is a display reference
const ids = bookings.map((booking) => booking.id);
import requests

response = requests.get(
    "https://api.fx-port.com/api/v1/history",
    params={"product": "esims", "limit": 50, "date_from": "2026-11-01"},
    headers={"Authorization": "Bearer fxp_test_YOUR_KEY"},
    timeout=30,
)
body = response.json()

Response example

An eSIM order, as the API returns it (a sandbox answer of the request above):

{
  "environment": "sandbox",
  "success": true,
  "data": [
    {
      "product": "esims",
      "id": "639417b4-b103-4ece-bd5d-850315322278",
      "bookingId": "FX-1793546602916",
      "booking_id": "FX-1793546602916",
      "status": "confirmed",
      "environment": "sandbox",
      "agencyId": "0b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d",
      "agency_id": "0b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d",
      "agentId": null,
      "agent_id": null,
      "currency": "DZD",
      "totalPrice": 468.84,
      "total_price": 468.84,
      "netPrice": 418.6,
      "b2b_price": 418.6,
      "agencyCommission": 50.24,
      "agency_commission": 50.24,
      "providerName": "Airalo",
      "provider_name": "Airalo",
      "supplierId": "airalo",
      "supplier_id": "airalo",
      "createdAt": "2026-11-01T15:23:22.961228+00:00",
      "created_at": "2026-11-01T15:23:22.961228+00:00",
      "updatedAt": "2026-11-01T15:23:22.961228+00:00",
      "updated_at": "2026-11-01T15:23:22.961228+00:00",
      "orderId": "20261101-106852",
      "order_id": "20261101-106852",
      "type": "esim",
      "packageName": "1 GB - 7 days • France",
      "package_name": "1 GB - 7 days • France",
      "iccid": "8900000540463077957",
      "customerEmail": "[email protected]",
      "customer_email": "[email protected]",
      "customer_first_name": "John",
      "customer_last_name": "Smith",
      "customer_phone": "+15555550123"
    }
  ],
  "pagination": { "page": 1, "limit": 2, "total": 80, "total_pages": 40, "hasMore": true, "has_more": true },
  "meta": {
    "agencyId": "0b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d",
    "agency_id": "0b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d",
    "environment": "sandbox",
    "product": "esims"
  }
}

The entries of the other products have the same first fifteen keys and their own keys after updatedAt. They are shown without their snake_case twins to keep them short:

{
  "product": "flights",
  "id": "8723790a-0417-46bb-8247-07254b214a4c",
  "bookingId": "Y7INFJ",
  "status": "awaiting_payment",
  "environment": "sandbox",
  "agencyId": "0b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d",
  "agentId": null,
  "currency": "DZD",
  "totalPrice": 32593.93,
  "netPrice": 32561.36,
  "agencyCommission": 32.57,
  "providerName": "Amadeus Algeria",
  "supplierId": "amadeus_aqc_dz_1",
  "createdAt": "2026-11-01T14:31:20.248661+00:00",
  "updatedAt": "2026-11-01T14:31:22.611902+00:00",
  "departureAirport": "ALG",
  "arrivalAirport": "CDG",
  "departureDate": "2026-12-15T07:15:00",
  "arrivalDate": "2026-12-15T09:45:00",
  "ticketNumber": null,
  "requireAcd": false,
  "voucherUrl": "https://files.example.com/flight-bookings/Y7INFJ-JOHN-SMITH.pdf",
  "voucherUrlWithPrice": "https://files.example.com/flight-bookings/Y7INFJ-JOHN-SMITH.pdf",
  "voucherUrlNoPrice": "https://files.example.com/flight-bookings/Y7INFJ-JOHN-SMITH-no-price.pdf"
}
{
  "product": "hotels",
  "id": "34a08cf3-dff6-45c6-bdae-882061aa78f5",
  "bookingId": "HMVXX4ZQ3",
  "status": "refunded",
  "environment": "sandbox",
  "agencyId": "0b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d",
  "agentId": null,
  "currency": "DZD",
  "totalPrice": 1484.97,
  "netPrice": 1482.0,
  "agencyCommission": 2.97,
  "providerName": "ETG - RateHawk",
  "supplierId": "ratehawk",
  "createdAt": "2026-11-01T14:22:00.924125+00:00",
  "updatedAt": "2026-11-01T14:22:32.992144+00:00",
  "hotelId": "test_hotel_do_not_book",
  "hotelName": "Test Hotel (Do Not Book) test",
  "checkinDate": "2026-12-01",
  "checkoutDate": "2026-12-04",
  "bookingMode": "standard",
  "voucherUrl": "https://files.example.com/hotel-bookings/HMVXX4ZQ3-Jane-Smith.pdf",
  "voucherUrlWithPrice": "https://files.example.com/hotel-bookings/HMVXX4ZQ3-Jane-Smith.pdf",
  "voucherUrlNoPrice": "https://files.example.com/hotel-bookings/HMVXX4ZQ3-Jane-Smith-no-price.pdf"
}
{
  "product": "transfers",
  "id": "4745c761-0737-421a-aaab-c90f9c0aca8f",
  "bookingId": "VIA-1782555657-QCF",
  "status": "refunded",
  "environment": "sandbox",
  "agencyId": "0b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d",
  "agentId": "5d6e7f80-91a2-4b3c-8d4e-5f6071829304",
  "currency": "DZD",
  "totalPrice": 15124.38,
  "netPrice": 15002.38,
  "agencyCommission": 122.0,
  "providerName": "AirportTransfer.com",
  "supplierId": null,
  "createdAt": "2026-06-27T10:20:59.188372+00:00",
  "updatedAt": "2026-06-27T10:29:28.684+00:00",
  "arrivalDate": "2026-08-14T16:00:00+00:00",
  "flightNumber": "593",
  "voucherUrl": null,
  "receiptUrl": "https://files.example.com/transfer-bookings/VIA-1782555657-QCF.pdf"
}

Summary fields

Every product

Field (twin)Description
productflights, hotels, esims or transfers
idThe internal id of the booking (UUID). Stable and unique: use it as your key
bookingId (booking_id)The public reference: the airline record locator of a flight (not unique across suppliers), the hotel booking id, FX- followed by a number for an eSIM, or the transfer reference
statusThe state of the booking (see below)
environmentsandbox or live
agencyId (agency_id)Your agency UUID
agentId (agent_id)The user of your agency who created the booking, or null when it was created through an API key without a user
currencyYour agency currency: the currency of every amount
totalPrice (total_price)What the traveler pays, with your commission
agencyCommission (agency_commission)Your commission as an amount. 0 when there is none
netPrice (b2b_price)The amount debited from your balance: totalPrice minus agencyCommission
providerName (provider_name)The supplier that fulfilled the booking
supplierId (supplier_id)The supplier id stored on the booking (see the note below)
createdAt (created_at), updatedAt (updated_at)ISO 8601, UTC

Flights: departureAirport, arrivalAirport (IATA), departureDate, arrivalDate (local, without a zone), ticketNumber (null until issued), requireAcd (require_acd), voucherUrl and voucherUrlWithPrice (the confirmation PDF with prices) and voucherUrlNoPrice (without prices, to give to the traveler). The voucher links are null while the PDF is generated.

Hotels: hotelId, hotelName (can be null on a failed booking), checkinDate, checkoutDate (YYYY-MM-DD), bookingMode, and the same three voucher links.

eSIMs: orderId (order_id, the supplier's order code), type (esim or topup), packageName (package_name), iccid, customerEmail (customer_email), customer_first_name, customer_last_name, customer_phone.

Transfers: arrivalDate, flightNumber, voucherUrl (the supplier voucher: null until a driver is assigned) and receiptUrl (FX-Port's receipt PDF, once the booking is confirmed).

supplierId is the id stored on the booking: amadeus_aqc_dz_1 and duffel_1 for flights, but ratehawk for hotels and airalo for eSIMs, while the supplier list calls the same suppliers worldota_1 and airalo_1. Do not match the two lists on the id.

Status values

StatusProductsMeaning
confirmedAllThe booking is confirmed
awaiting_paymentFlightsA held booking that is not paid yet. pending is accepted as another name in the filter
cancelledFlightsThe booking was cancelled
failedFlights, eSIMsThe supplier refused the booking
refundedFlights, hotels, transfersThe booking was refunded
partial_refundFlightsPart of the booking was refunded

These are the values seen today; a product can use others, and a filter on a status nothing has answers an empty list.

Errors

HTTPcodeCause
400invalid_productproduct is not one of the allowed values (details.allowed lists them)
400invalid_statusstatus is not a plain status name (letters, digits, _, spaces or hyphens, at most 32 characters)
400invalid_date, invalid_date_rangeA date is not valid, or date_from is after date_to
400agency_id_not_allowedAn API key sent agency_id
401authentication_required, invalid_api_keyMissing or invalid API key
422validation_errorpage is below 1 or above 10,000, or limit is above 100
429rate_limit_exceededOver 6,000 requests per minute for this key
503service_overloadedThe service is shedding load for a moment (its database pool is full). Nothing was read: retry after the seconds in Retry-After (2 to 5)
PreviousBalance historyNext Booking detail

On this page

  • Query parameters
  • Pagination
  • Request examples
  • Response example
  • Summary fields
  • Status values
  • Errors

© 2026 FX-Port

TermsPrivacy[email protected]