Getting Started
Ready to integrate?
Get your API key and start sending requests to the Flyo partner API.
Flyo's external partner APIs let you register flight bookings for automated web check-in, poll the current status of a check-in request, and list all your historical check-in requests.
Because these endpoints are consumed by external systems, all paths below are relative paths. Append them to the deployment-specific host your integration points at.
Every request must include a valid X-API-Key header. Get your API key from the Flyo partner dashboard. The key is static and remains valid until it is revoked from the dashboard; there is no separate expiry or refresh flow.
All request and response bodies use JSON. Timestamps are ISO 8601 UTC strings. IATA codes are exactly three uppercase letters.
Authentication
External partner endpoints require an API key passed in the X-API-Key header. The key identifies your enterprise and is used for both authentication and per-key rate limiting.
When a request arrives, the key is validated against the database first. Only if it is not found there do we fall back to the legacy environment-based key list.
Validation rules: the header must be present and non-empty; it must match an active key; revoked, disabled, or unknown keys receive 401. There is no token expiry or refresh; a key stays active until revoked. In development mode only, a default environment key can be used for testing. Production integrations must use a real dashboard-issued key.
GET /extPartner/api/webcheckin/requests
X-API-Key: flyo_<issued-key>
Content-Type: application/jsonRate Limits
Rate limiting is enforced per API key using a rolling window. Two limits apply independently:
- 60 requests per minute
- 1,000 requests per hour
When either limit is exceeded the API returns HTTP 429 with a retryAfter value in seconds. Wait at least that many seconds before retrying.
Subscribe also consumes a quota unit in addition to the rate limit.
Error Format
All error responses follow a single JSON shape. The success field is always false. The error field is a stable machine-readable code you can branch on. The message field is a human-readable explanation. Additional context is included only when relevant.
{
"success": false,
"error": "VALIDATION_ERROR",
"message": "Missing or malformed request data"
}Common Errors
| HTTP Status | Message |
|---|---|
| 400 | VALIDATION_ERROR: missing or malformed request data. |
| 401 | Missing, invalid, disabled, or revoked API key. |
| 402 | QUOTA_EXHAUSTED: no available web-check-in entitlement or quota exhausted. |
| 404 | NOT_FOUND: the requested check-in or booking does not exist or belongs to another enterprise. |
| 409 | Conflict: the resource cannot be modified in its current state. |
| 422 | REJECTED: journey rule rejection such as departure too close, unsupported airline, or invalid route. |
| 429 | Rate limit exceeded. retryAfter is returned in seconds. |
| 500 | INTERNAL_ERROR: an unexpected server error occurred. |
Pagination
The list endpoint uses offset pagination. page is zero-based, so the first page is 0. limit defaults to 25 and is clamped to a maximum of 100. If you omit the parameters you receive page 0 with 25 items.
The response always includes a pagination object with the page you requested, the actual limit applied, the total matching records, and the total number of pages. Use totalPages to know when you have reached the end of the result set.
{
"success": true,
"data": [],
"pagination": {
"page": 0,
"limit": 25,
"total": 47,
"totalPages": 2
}
}Webhooks
When you subscribe a booking with callbackData, Flyo pushes status changes to your callbackUrl instead of requiring you to poll. Webhooks are sent for the event kind webcheckin.update whenever the check-in attempt changes state.
The callbackData object requires callbackUrl, clientId, clientName, and auth_header. The auth_header must be in the format '<Header-Name>: <Header-Value>' and the header name must be either X-API-Key or Authorization. Flyo forwards this header exactly in every webhook request so your endpoint can verify it.
Webhook delivery is handled through an internal SQS queue. Retries and backoff are managed by the queue consumer; your endpoint should respond with a 2xx status code so delivery is considered successful.
Flyo does not sign the webhook body or add a provider signature header. Authenticate the request using the auth_header value you configured.
{
"occurredAt": "2026-09-02T09:00:00.000Z",
"checkin_id": "CHK-783245",
"changes": {
"status": "COMPLETED",
"sub_status": "BOARDING_PASS_AVAILABLE",
"checkin_message": "Check-in completed and boarding passes are available",
"missing_info": [],
"boarding_passes": [
"https://files.example.com/boarding-pass.pdf"
]
}
}External Webcheckin APIs
Use these endpoints from an external system to subscribe bookings for automated web check-in, poll for status, and list historical requests.
/extPartner/api/webcheckin/subscribeCreate Web Check-in Request
X-API-Key: flyo_<issued-key>Registers a partner booking for automated airline web check-in under the enterprise identified by the API key. Requires an active web-check-in entitlement.
Validates the partner booking payload, checks entitlement and quota, applies journey rules, creates or reuses a partner-scoped check-in attempt, and returns the attempt plus quota details.
Missing passenger or passport information does not automatically reject the request. The attempt can be stored as SCHEDULED with a missing-information sub-status, allowing you to update the booking before automation runs.
If the flight is already inside the check-in window and all required information is present, automation may trigger immediately. Otherwise the attempt is queued for the check-in window.
The response message is one of SCHEDULED, ALREADY_SUBSCRIBED, or REJECTED. When the message is REJECTED, the reason field explains why.
Request
curl -X POST "/extPartner/api/webcheckin/subscribe" \
-H "X-API-Key: flyo_<issued-key>" \
-H "Content-Type: application/json" \
-d '{"pnr":"ABC123","flights":[{"airline":"AI","flight_number":"AI302","origin":"DEL","destination":"DXB","departure_datetime":"2026-09-02T04:30:00Z","arrival_datetime":"2026-09-02T07:45:00Z"}],"passengers":[{"first_name":"John","last_name":"Doe","email":"john@example.com","phone":"+911234567890","date_of_birth":"1995-07-20","passport":{"number":"N1234567","expiry_date":"2030-05-01","nationality":"IN"},"seat_preference":{"row_preference":"front","column_preference":"window"}}],"callbackData":{"clientId":"acme","clientName":"Acme Travel","callbackUrl":"https://partner.example.com/webhooks/flyo","auth_header":"X-API-Key: A1B2C3D4E5F6G7H8"}}'{
"pnr": "ABC123",
"flights": [
{
"airline": "AI",
"flight_number": "AI302",
"origin": "DEL",
"destination": "DXB",
"departure_datetime": "2026-09-02T04:30:00Z",
"arrival_datetime": "2026-09-02T07:45:00Z"
}
],
"passengers": [
{
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "+911234567890",
"date_of_birth": "1995-07-20",
"passport": {
"number": "N1234567",
"expiry_date": "2030-05-01",
"nationality": "IN"
},
"seat_preference": {
"row_preference": "front",
"column_preference": "window"
}
}
],
"callbackData": {
"clientId": "acme",
"clientName": "Acme Travel",
"callbackUrl": "https://partner.example.com/webhooks/flyo",
"auth_header": "X-API-Key: A1B2C3D4E5F6G7H8"
}
}Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
| pnr | string | Yes | Airline record locator. |
| flights | array | Yes | One or more flight legs in travel order. All legs must use the same airline. |
| flights[].airline | IATA code (3 letters) | Yes | Airline IATA code. |
| flights[].flight_number | string | Yes | Flight number including airline prefix. |
| flights[].origin | IATA airport code | Yes | Origin airport. |
| flights[].destination | IATA airport code | Yes | Destination airport. |
| flights[].departure_datetime | ISO 8601 timestamp | Yes | Departure date and time in ISO 8601 UTC format. |
| flights[].arrival_datetime | ISO 8601 timestamp | No | Arrival date and time in ISO 8601 UTC format. |
| passengers | array | Yes | Non-empty passenger list. |
| passengers[].first_name | string | Yes | Passenger first name. |
| passengers[].last_name | string | Yes | Passenger last name. |
| passengers[].email | email string | No | Passenger email address. |
| passengers[].phone | E.164 phone string | No | Passenger phone number. |
| passengers[].date_of_birth | YYYY-MM-DD | No | Passenger date of birth. |
| passengers[].passport | object | No | Passport details used by airline check-in. |
| passengers[].passport.number | string | No | Passport number. |
| passengers[].passport.expiry_date | YYYY-MM-DD | No | Passport expiry date. |
| passengers[].passport.nationality | ISO 3166-1 alpha-2 | No | Passport nationality country code. |
| passengers[].seat_preference | object | No | Optional seat preference. |
| passengers[].seat_preference.row_preference | enum: front | middle | back | No | Preferred row zone. |
| passengers[].seat_preference.column_preference | enum: window | aisle | middle | No | Preferred seat column. |
| callbackData | object | No | Callback registration for push status updates. |
| callbackData.clientId | string | Yes* | Partner callback client identifier. Required when callbackData is provided. |
| callbackData.clientName | string | Yes* | Partner callback client name. Required when callbackData is provided. |
| callbackData.callbackUrl | HTTPS URL | Yes* | URL that receives status events. Required when callbackData is provided. |
| callbackData.auth_header | string | Yes* | Webhook auth header in '<Header-Name>: <Header-Value>' format. Header name must be X-API-Key or Authorization. Required when callbackData is provided. |
Response
{
"success": true,
"message": "SCHEDULED",
"booking_id": 123,
"checkin_id": "CHK-783245",
"status": "SCHEDULED",
"sub_status": "MISSING_INFO",
"missing_info": [
{ "type": "MISSING_PASSPORT" }
],
"status_message": "Missing passport information",
"quota": {
"included_units": 100,
"consumed_units": 34
}
}Response Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | Whether the operation succeeded. |
| message | enum: SCHEDULED | ALREADY_SUBSCRIBED | REJECTED | High-level result of the subscription. |
| reason | string | undefined | Present when message is REJECTED. |
| booking_id | number | Internal booking identifier. |
| checkin_id | string | Public check-in identifier. |
| status | string | Current high-level status. |
| sub_status | string | Detailed sub-status. |
| missing_info | array | List of missing information items, if any. |
| status_message | string | Human-readable status explanation. |
| quota | object | undefined | Enterprise quota snapshot. |
| quota.included_units | number | Included web-check-in units. |
| quota.consumed_units | number | Consumed web-check-in units. |
Errors
| HTTP Status | Message |
|---|---|
| 400 | VALIDATION_ERROR: missing or malformed request data. |
| 401 | Missing, invalid, disabled, or revoked API key. |
| 402 | QUOTA_EXHAUSTED: no available entitlement or quota exhausted. |
| 422 | REJECTED: journey rule rejection, such as departure too close, unsupported airline, or invalid route. |
| 429 | Rate limit exceeded. retryAfter is returned in seconds. |
/extPartner/api/webcheckin/status?checkin_id=CHK-...Get Web Check-in Status
X-API-Key: flyo_<issued-key>Returns the latest status of one check-in request belonging to the enterprise identified by the API key.
Looks up the attempt by checkin_id and the authenticated partnerId, then returns the normalized partner-facing status, missing info, boarding passes, and timestamps.
A check-in belonging to another enterprise is indistinguishable from a missing check-in and returns 404.
Request
curl -X GET "/extPartner/api/webcheckin/status?checkin_id=CHK-783245" \
-H "X-API-Key: flyo_<issued-key>"Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
| checkin_id | string | Yes | Public check-in identifier returned by the create API. checkinId is also accepted as a compatibility alias. |
Response
{
"success": true,
"checkin_id": "CHK-783245",
"booking_id": 123,
"status": "COMPLETED",
"sub_status": "BOARDING_PASS_AVAILABLE",
"checkin_message": "Check-in completed and boarding passes are available",
"missing_info": [],
"boarding_passes": [
"https://files.example.com/boarding-pass.pdf"
],
"last_updated": "2026-09-02T09:00:00.000Z"
}Response Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | Whether the operation succeeded. |
| checkin_id | string | Public check-in identifier. |
| booking_id | number | Internal booking identifier. |
| status | enum: SCHEDULED | IN_PROGRESS | COMPLETED | FAILED | Current normalized status. |
| sub_status | string | Detailed sub-status. |
| checkin_message | string | Human-readable status explanation. |
| missing_info | array | List of missing information items, if any. |
| boarding_passes | array of HTTPS URLs | Boarding-pass URLs, when available. |
| last_updated | ISO 8601 timestamp | ISO timestamp of the latest update. |
Errors
| HTTP Status | Message |
|---|---|
| 400 | checkin_id is missing. |
| 401 | Missing, invalid, disabled, or revoked API key. |
| 404 | The check-in does not exist or belongs to another enterprise. |
| 429 | Rate limit exceeded. retryAfter is returned in seconds. |
/extPartner/api/webcheckin/requests?page=0&limit=25&status=COMPLETEDList Enterprise Check-in Requests
X-API-Key: flyo_<issued-key>Returns paginated web check-in request summaries for the enterprise identified by the API key.
Returns the enterprise's paginated, normalized web-check-in request summaries. The result is enterprise-scoped, not scoped by the individual API key used to call this endpoint.
Two API keys belonging to the same enterprise must see the same set of enterprise check-in requests.
page is zero-based. limit defaults to 25 and is clamped between 1 and 100. totalPages is derived from the total count and the applied limit.
Request
curl -X GET "/extPartner/api/webcheckin/requests?page=0&limit=25&status=COMPLETED" \
-H "X-API-Key: flyo_<issued-key>"Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
| page | integer >= 0 | No | Zero-based page number. Defaults to 0. |
| limit | integer 1-100 | No | Items per page. Defaults to 25; values above 100 are clamped to 100. |
| status | enum: SCHEDULED | IN_PROGRESS | COMPLETED | FAILED | No | Filter by check-in status. |
Response
{
"success": true,
"data": [
{
"checkin_id": "CHK-783245",
"booking_id": 123,
"pnr": "ABC123",
"origin": "DEL",
"destination": "DXB",
"departure_date": "2026-09-02T04:30:00Z",
"airline": "AI",
"flight_number": "AI302",
"status": "COMPLETED",
"sub_status": "BOARDING_PASS_AVAILABLE",
"checkin_message": "Check-in completed and boarding passes are available",
"missing_info": [],
"boarding_passes": [
"https://files.example.com/boarding-pass.pdf"
],
"scheduled_time": "2026-09-02T01:30:00Z",
"created_at": "2026-08-20T10:00:00Z",
"last_updated": "2026-09-02T09:00:00Z"
}
],
"pagination": {
"page": 0,
"limit": 25,
"total": 1,
"totalPages": 1
}
}Response Fields
| Field | Type | Description |
|---|---|---|
| success | boolean | Whether the operation succeeded. |
| data | array | List of check-in request summaries. |
| data[].checkin_id | string | Public check-in identifier. |
| data[].booking_id | number | Internal booking identifier. |
| data[].pnr | string | Airline record locator. |
| data[].origin | IATA airport code | Origin airport IATA code. |
| data[].destination | IATA airport code | Destination airport IATA code. |
| data[].departure_date | ISO 8601 timestamp | Departure date and time. |
| data[].airline | IATA code | Airline IATA code. |
| data[].flight_number | string | Flight number. |
| data[].status | enum: SCHEDULED | IN_PROGRESS | COMPLETED | FAILED | Current normalized status. |
| data[].sub_status | string | Detailed sub-status. |
| data[].checkin_message | string | Human-readable status explanation. |
| data[].missing_info | array | List of missing information items. |
| data[].boarding_passes | array of HTTPS URLs | Boarding-pass URLs, when available. |
| data[].scheduled_time | ISO 8601 timestamp | null | Scheduled automation time. |
| data[].created_at | ISO 8601 timestamp | Request creation timestamp. |
| data[].last_updated | ISO 8601 timestamp | Latest update timestamp. |
| pagination | object | Pagination metadata. |
| pagination.page | integer | Current zero-based page. |
| pagination.limit | integer | Items per page (1-100). |
| pagination.total | integer | Total matching items. |
| pagination.totalPages | integer | Total pages. |
Errors
| HTTP Status | Message |
|---|---|
| 400 | VALIDATION_ERROR: invalid page, limit, or filter value. |
| 401 | Missing, invalid, disabled, or revoked API key. |
| 429 | Rate limit exceeded. retryAfter is returned in seconds. |