Developer Reference

API Documentation

View .md
VR

Written by Varsha Reddy, SDE at Flyo.ai

varsha@flyo.ai

Quickstart: your first check-in

1. Get access and configure your server

Get an API key from the partner dashboard and ask the Flyo team for the API base URL for your environment. Use the API base URL without a trailing slash. The documentation website and dashboard URL are not your API base URL.

Ready to integrate?

Get your API key and start sending requests to the Flyo partner API.

Get your API key
Configure your environment
export FLYO_API_BASE_URL='https://<API-host-provided-for-your-environment>'
export FLYO_API_KEY='<your-dashboard-issued-key>'

2. Choose how to receive updates

Start with polling for the quickest setup. For webhooks, include callbackData in your first subscribe request. Retrying an active subscription does not add or change its callback configuration. If the existing attempt has no callback, continue polling.

Use the webhook subscription example instead of the polling example below

3. Subscribe your first booking

Replace the example flight date with a real future departure at least 6 hours away. Send the departure clock in the origin airport's local time, without converting it to UTC.

Subscribe a domestic booking
curl -X POST "$FLYO_API_BASE_URL/extPartner/api/webcheckin/subscribe" \
  -H "X-API-Key: $FLYO_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "pnr": "ABC123",
  "flights": [
    {
      "airline": "6E",
      "flight_number": "6E203",
      "origin": "DEL",
      "destination": "BOM",
      "departure_datetime": "2030-09-20T10:00:00",
      "arrival_datetime": "2030-09-20T12:00:00"
    }
  ],
  "passengers": [
    {
      "first_name": "John",
      "last_name": "Doe",
      "email": "john@example.com"
    }
  ]
}'
Example response: HTTP 200
{
  "success": true,
  "message": "SCHEDULED",
  "booking_id": 123,
  "checkin_id": "CHK-783245",
  "status": "SCHEDULED",
  "sub_status": "COMPLETE_INFO",
  "missing_info": [],
  "status_message": "Check-in scheduled",
  "quota": {
    "included_units": 100,
    "consumed_units": 1
  }
}

4. Save the IDs and check status

A successful response gives you checkin_id and booking_id. Save them with your own booking reference. message says whether the subscription is new or already exists; status says where check-in currently stands.

Use your returned checkin_id
export FLYO_CHECKIN_ID='<checkin_id-from-your-subscribe-response>'
Poll status
curl "$FLYO_API_BASE_URL/extPartner/api/webcheckin/status?checkin_id=$FLYO_CHECKIN_ID" \
  -H "X-API-Key: $FLYO_API_KEY"
Example completed status: HTTP 200
{
  "success": true,
  "checkin_id": "CHK-783245",
  "booking_id": 123,
  "status": "COMPLETED",
  "sub_status": "BOARDING_PASS_AVAILABLE",
  "checkin_message": "Checkin completed and boarding passes are available",
  "missing_info": [],
  "boarding_passes": [
    "https://files.example.com/boarding-pass.pdf"
  ],
  "last_updated": "2030-09-18T05:00:00.000Z"
}

5. Handle the current result

If missing_info contains items, supply the missing details through update. If boarding_passes contains URLs, show those downloads to the traveller. COMPLETED with an empty boarding_passes array means check-in finished but a pass is not available yet.

missing_info is not empty (including IN_PROGRESS / MISSING_INFO)
Collect the requested information. For passenger changes, resend the complete passenger list, preserving unchanged details and documents. For MISSING_PNR, correct payload.pnr, then send a complete passengers update to resume. If update returns 409 NOT_UPDATABLE, stop updating and inspect the current status.
SCHEDULED or IN_PROGRESS, with no missing_info
Wait for fulfillment and check status or receive webhook updates. A new subscription can already be IN_PROGRESS. Public status alone does not determine whether updates are allowed.
COMPLETED, with boarding_passes URLs
Offer the URLs as downloads. The array does not identify which passenger or flight each URL belongs to.
COMPLETED, without boarding_passes URLs
Show that check-in completed and the pass is not available yet. Keep checking status or listening for events; do not create a second subscription just to obtain a pass.
FAILED or CANCELLED
Inspect checkin_message and the latest status before deciding whether a new attempt is appropriate. A new attempt may consume quota; do not automatically resubscribe in a loop.
See the missing-information recovery example

Integration examples

These are independent scenarios unless an example explicitly continues the preceding request. Do not run every example against the same booking. Dates, identifiers and responses are illustrative; replace dates, passenger details, returned IDs and file paths before running a request.

International booking: complete passport details

Each passenger needs passport number, issue date, expiry date, place of issue and nationality. Passport nationality can fall back to passenger nationality. A scan alone does not supply these fields.

Request
curl -X POST "$FLYO_API_BASE_URL/extPartner/api/webcheckin/subscribe" \
  -H "X-API-Key: $FLYO_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "pnr": "ABC123",
  "flights": [
    {
      "airline": "AI",
      "flight_number": "AI302",
      "origin": "DEL",
      "destination": "DXB",
      "departure_datetime": "2030-09-20T10:00:00",
      "arrival_datetime": "2030-09-20T12:00:00"
    }
  ],
  "passengers": [
    {
      "first_name": "John",
      "last_name": "Doe",
      "email": "john@example.com",
      "phone": "9876543210",
      "country_code": "+91",
      "date_of_birth": "1995-07-20",
      "nationality": "IN",
      "country_of_residence": "IN",
      "passport": {
        "number": "N1234567",
        "date_of_issue": "2020-05-01",
        "expiry_date": "2035-05-01",
        "place_of_issue": "DELHI",
        "nationality": "IN"
      },
      "documents": [
        {
          "type": "VISA",
          "document_number": "V123456",
          "issuing_country": "AE",
          "expiry_date": "2035-05-01"
        }
      ],
      "seat_preference": {
        "row_preference": "rear",
        "column_preference": "window"
      }
    }
  ],
  "callbackData": {
    "callbackUrl": "https://partner.example.com/webhooks/flyo",
    "auth_header": "Authorization: Bearer <your-callback-secret>"
  }
}'
Example response: HTTP 200
{
  "success": true,
  "message": "SCHEDULED",
  "booking_id": 123,
  "checkin_id": "CHK-783245",
  "status": "SCHEDULED",
  "sub_status": "COMPLETE_INFO",
  "missing_info": [],
  "status_message": "Check-in scheduled",
  "quota": {
    "included_units": 100,
    "consumed_units": 1
  }
}

Next action: Save checkin_id. Inspect missing_info and supply any missing details before automation runs.

Multiple passengers and connecting flights

Use one passengers entry per traveller. One-way legs must connect end-to-end, share the same airline and never revisit an airport. Send the complete itinerary; legs are sorted by departure instant.

Request
curl -X POST "$FLYO_API_BASE_URL/extPartner/api/webcheckin/subscribe" \
  -H "X-API-Key: $FLYO_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "pnr": "ABC123",
  "flights": [
    {
      "airline": "6E",
      "flight_number": "6E203",
      "origin": "DEL",
      "destination": "BOM",
      "departure_datetime": "2030-09-20T10:00:00",
      "arrival_datetime": "2030-09-20T12:00:00"
    },
    {
      "airline": "6E",
      "flight_number": "6E2450",
      "origin": "BOM",
      "destination": "BLR",
      "departure_datetime": "2030-09-20T15:00:00"
    }
  ],
  "passengers": [
    {
      "first_name": "John",
      "last_name": "Doe",
      "email": "john@example.com"
    },
    {
      "first_name": "Aman",
      "last_name": "Shah",
      "email": "aman@example.com"
    }
  ]
}'
Example response: HTTP 200
{
  "success": true,
  "message": "SCHEDULED",
  "booking_id": 123,
  "checkin_id": "CHK-783245",
  "status": "SCHEDULED",
  "sub_status": "COMPLETE_INFO",
  "missing_info": [],
  "status_message": "Check-in scheduled",
  "quota": {
    "included_units": 100,
    "consumed_units": 1
  }
}

Next action: Track the booking using its one checkin_id. Boarding-pass URLs are a flat array; the API does not expose passenger or segment mapping.

Subscribe now, supply missing information later

A missing email, incomplete international passport or unusable PNR can produce MISSING_INFO instead of rejecting the booking. Passenger names and a non-empty passenger list are still required.

Request
curl -X POST "$FLYO_API_BASE_URL/extPartner/api/webcheckin/subscribe" \
  -H "X-API-Key: $FLYO_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "pnr": "ABC123",
  "flights": [
    {
      "airline": "6E",
      "flight_number": "6E203",
      "origin": "DEL",
      "destination": "BOM",
      "departure_datetime": "2030-09-20T10:00:00",
      "arrival_datetime": "2030-09-20T12:00:00"
    }
  ],
  "passengers": [
    {
      "first_name": "Priya",
      "last_name": "Sharma"
    }
  ]
}'
Example response: HTTP 200
{
  "success": true,
  "message": "SCHEDULED",
  "booking_id": 123,
  "checkin_id": "CHK-783245",
  "status": "SCHEDULED",
  "sub_status": "MISSING_INFO",
  "missing_info": [
    {
      "type": "MISSING_EMAIL"
    }
  ],
  "status_message": "Missing email address",
  "quota": {
    "included_units": 100,
    "consumed_units": 1
  }
}

Next action: Continue with the next example to add Priya’s email, using the checkin_id returned by this subscription. At least one valid email across the passenger list is needed for automation.

Continue the missing-email example: add Priya’s email

This continues the preceding missing-email subscription. Replace CHK-783245 with its returned checkin_id. Keep Priya Sharma as the passenger and add her email; resend the whole list, not just the changed field.

Request
curl -X POST "$FLYO_API_BASE_URL/extPartner/api/webcheckin/update" \
  -H "X-API-Key: $FLYO_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "checkin_id": "CHK-783245",
  "type": "passengers",
  "passengers": [
    {
      "first_name": "Priya",
      "last_name": "Sharma",
      "email": "priya@example.com"
    }
  ]
}'
Example response: HTTP 200
{
  "success": true,
  "type": "passengers",
  "operation": "update",
  "data": {
    "checkin_id": "CHK-783245",
    "booking_id": 123,
    "status": "SCHEDULED",
    "sub_status": "COMPLETE_INFO",
    "checkin_message": "Check-in scheduled",
    "missing_info": [],
    "boarding_passes": [],
    "last_updated": "2030-09-16T10:30:00.000Z"
  }
}

Next action: Use status to follow this same checkin_id. The example shows a future scheduled attempt; completing the data inside the check-in window may start automation immediately. A 409 means the attempt is no longer editable; stop updating and inspect status.

Update passengers: resend the complete list

This replaces every passenger and their fields; it is not a partial patch. Include unchanged passengers, existing passport/document URLs and any other details you want to retain. Do not resend an old file_field without attaching its file.

Request
curl -X POST "$FLYO_API_BASE_URL/extPartner/api/webcheckin/update" \
  -H "X-API-Key: $FLYO_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "checkin_id": "CHK-783245",
  "type": "passengers",
  "passengers": [
    {
      "first_name": "John",
      "last_name": "Doe",
      "email": "john@example.com",
      "phone": "9876543210",
      "country_code": "+91",
      "date_of_birth": "1995-07-20",
      "nationality": "IN",
      "country_of_residence": "IN",
      "passport": {
        "number": "N1234567",
        "date_of_issue": "2020-05-01",
        "expiry_date": "2035-05-01",
        "place_of_issue": "DELHI",
        "nationality": "IN"
      },
      "documents": [
        {
          "type": "VISA",
          "document_number": "V123456",
          "issuing_country": "AE",
          "expiry_date": "2035-05-01"
        }
      ],
      "seat_preference": {
        "row_preference": "rear",
        "column_preference": "window"
      }
    }
  ]
}'
Example response: HTTP 200
{
  "success": true,
  "type": "passengers",
  "operation": "update",
  "data": {
    "checkin_id": "CHK-783245",
    "booking_id": 123,
    "status": "SCHEDULED",
    "sub_status": "COMPLETE_INFO",
    "checkin_message": "Check-in scheduled",
    "missing_info": [],
    "boarding_passes": [],
    "last_updated": "2030-09-16T10:30:00.000Z"
  }
}

Next action: Read the returned data.status and missing_info. Completing the data may start automation immediately if the window is open. A 409 means this attempt is no longer editable.

Correct a PNR

PNR changes belong in payload.pnr. A top-level pnr is not used by update. Without files, you may identify the booking with booking_id instead of checkin_id.

Request
curl -X POST "$FLYO_API_BASE_URL/extPartner/api/webcheckin/update" \
  -H "X-API-Key: $FLYO_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "checkin_id": "CHK-783245",
  "type": "pnr",
  "payload": {
    "pnr": "DEF456"
  }
}'
Example response: HTTP 200
{
  "success": true,
  "type": "pnr",
  "operation": "update",
  "data": {
    "checkin_id": "CHK-783245",
    "booking_id": 123,
    "status": "SCHEDULED",
    "sub_status": "COMPLETE_INFO",
    "checkin_message": "Check-in scheduled",
    "missing_info": [],
    "boarding_passes": [],
    "last_updated": "2030-09-16T10:30:00.000Z"
  }
}

Next action: PNR updates refresh missing_info but do not start or reschedule automation. If you need to resume a missing-info attempt, follow with a complete passengers update. Public status alone does not guarantee update eligibility.

Upload a passport and supporting document

Use multipart/form-data. Each file_field must exactly match a file-part name. JSON-stringify the passenger list. For subscribe, also send pnr and JSON-stringified flights. Files require checkin_id on update. Limits: 30 files, 10 MiB each, PDF or image MIME types.

Request
curl -X POST "$FLYO_API_BASE_URL/extPartner/api/webcheckin/update" \
  -H "X-API-Key: $FLYO_API_KEY" \
  -F 'checkin_id=CHK-783245' \
  -F 'type=passengers' \
  -F 'passengers=[{"first_name":"John","last_name":"Doe","email":"john@example.com","phone":"9876543210","country_code":"+91","date_of_birth":"1995-07-20","nationality":"IN","country_of_residence":"IN","passport":{"number":"N1234567","date_of_issue":"2020-05-01","expiry_date":"2035-05-01","place_of_issue":"DELHI","nationality":"IN","file_field":"traveller-passport"},"documents":[{"type":"VISA","document_number":"V123456","issuing_country":"AE","expiry_date":"2035-05-01","file_field":"traveller-visa"}],"seat_preference":{"row_preference":"rear","column_preference":"window"}}]' \
  -F 'traveller-passport=@/path/to/traveller-passport.pdf;type=application/pdf' \
  -F 'traveller-visa=@/path/to/traveller-visa.pdf;type=application/pdf'
Example response: HTTP 200
{
  "success": true,
  "type": "passengers",
  "operation": "update",
  "data": {
    "checkin_id": "CHK-783245",
    "booking_id": 123,
    "status": "SCHEDULED",
    "sub_status": "COMPLETE_INFO",
    "checkin_message": "Check-in scheduled",
    "missing_info": [],
    "boarding_passes": [],
    "last_updated": "2030-09-16T10:30:00.000Z"
  }
}

Next action: Let curl set the multipart boundary. Uploaded files do not replace the typed passport details. These endpoints do not return the storage URLs created by uploads. For later passenger replacements, retain any document URLs and metadata you already know; otherwise reattach the files. Uploads do not make the passport complete on their own.

Retry an active subscription

A matching active booking returns ALREADY_SUBSCRIBED without another quota charge. The match uses your enterprise, PNR and full first-leg local departure timestamp; changing the airline for that match rejects the request. Resend the authoritative payload: subscribe can update passenger and flight data before detecting the duplicate.

Request
curl -X POST "$FLYO_API_BASE_URL/extPartner/api/webcheckin/subscribe" \
  -H "X-API-Key: $FLYO_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "pnr": "ABC123",
  "flights": [
    {
      "airline": "6E",
      "flight_number": "6E203",
      "origin": "DEL",
      "destination": "BOM",
      "departure_datetime": "2030-09-20T10:00:00",
      "arrival_datetime": "2030-09-20T12:00:00"
    }
  ],
  "passengers": [
    {
      "first_name": "John",
      "last_name": "Doe",
      "email": "john@example.com"
    }
  ]
}'
Example response: HTTP 200
{
  "success": true,
  "message": "ALREADY_SUBSCRIBED",
  "booking_id": 123,
  "checkin_id": "CHK-783245",
  "status": "SCHEDULED",
  "sub_status": "COMPLETE_INFO",
  "missing_info": [],
  "status_message": "Check-in scheduled"
}

Next action: Reuse the returned checkin_id. Entitlement, quota and departure checks still apply before duplicate reuse, so a retry can instead return 402 or 422. Failed or cancelled attempts can permit a new charged attempt.

Resubscribe to an already completed Flyo attempt

A stored completed attempt is rejected. ALREADY_SUBSCRIBED does not mean Flyo queried the airline for a traveller's independently completed check-in.

Request
curl -X POST "$FLYO_API_BASE_URL/extPartner/api/webcheckin/subscribe" \
  -H "X-API-Key: $FLYO_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "pnr": "ABC123",
  "flights": [
    {
      "airline": "6E",
      "flight_number": "6E203",
      "origin": "DEL",
      "destination": "BOM",
      "departure_datetime": "2030-09-20T10:00:00",
      "arrival_datetime": "2030-09-20T12:00:00"
    }
  ],
  "passengers": [
    {
      "first_name": "John",
      "last_name": "Doe",
      "email": "john@example.com"
    }
  ]
}'
Example response: HTTP 422
{
  "success": false,
  "error": "REJECTED",
  "message": "Webcheckin already completed"
}

Next action: Use the original checkin_id to fetch its outcome. After a timeout or 500, inspect status or requests before retrying; do not assume no booking was created.

Handle a 422 after a passenger update was saved

If a passengers update completes missing information with less than 6 hours to departure, resuming automation can reject after the passenger changes have committed.

Request
curl -X POST "$FLYO_API_BASE_URL/extPartner/api/webcheckin/update" \
  -H "X-API-Key: $FLYO_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "checkin_id": "CHK-783245",
  "type": "passengers",
  "passengers": [
    {
      "first_name": "John",
      "last_name": "Doe",
      "email": "john@example.com",
      "phone": "9876543210",
      "country_code": "+91",
      "date_of_birth": "1995-07-20",
      "nationality": "IN",
      "country_of_residence": "IN",
      "passport": {
        "number": "N1234567",
        "date_of_issue": "2020-05-01",
        "expiry_date": "2035-05-01",
        "place_of_issue": "DELHI",
        "nationality": "IN"
      },
      "documents": [
        {
          "type": "VISA",
          "document_number": "V123456",
          "issuing_country": "AE",
          "expiry_date": "2035-05-01"
        }
      ],
      "seat_preference": {
        "row_preference": "rear",
        "column_preference": "window"
      }
    }
  ]
}'
Example response: HTTP 422
{
  "success": false,
  "error": "REJECTED",
  "message": "Departure date is too close or in the past (less than 6 hours)",
  "reason_code": "DEPARTURE_TOO_CLOSE"
}

Next action: Poll status for the latest state. The changes may already be saved; do not assume rollback, create another subscription or loop on retries.

Check whether a boarding pass is available

The status endpoint returns the current attempt. COMPLETED may have BOARDING_PASS_NOT_AVAILABLE and an empty boarding_passes array.

Request
curl "$FLYO_API_BASE_URL/extPartner/api/webcheckin/status?checkin_id=CHK-783245" \
  -H "X-API-Key: $FLYO_API_KEY"
Example response: HTTP 200
{
  "success": true,
  "checkin_id": "CHK-783245",
  "booking_id": 123,
  "status": "COMPLETED",
  "sub_status": "BOARDING_PASS_NOT_AVAILABLE",
  "checkin_message": "Checkin completed, boarding pass is not available yet",
  "missing_info": [],
  "boarding_passes": [],
  "last_updated": "2030-09-18T05:00:00.000Z"
}

Next action: Show a download when URLs arrive in boarding_passes. Continue polling or listening for events if there are no URLs yet; do not create a second subscription solely to obtain a pass.

List requests and move to the next page

page starts at 0; limit defaults to 25 and has a maximum of 100. status filters use normalized states. An unknown status filter is ignored, returning an unfiltered list. Always send integer page and limit values.

Request
curl "$FLYO_API_BASE_URL/extPartner/api/webcheckin/requests?page=0&limit=25&status=COMPLETED" \
  -H "X-API-Key: $FLYO_API_KEY"
Example response: HTTP 200
{
  "success": true,
  "data": [
    {
      "checkin_id": "CHK-783245",
      "booking_id": 123,
      "pnr": "ABC123",
      "origin": "DEL",
      "destination": "DXB",
      "departure_datetime": "2030-09-20T10:00:00.000Z",
      "airline": "AI",
      "flight_number": "AI302",
      "status": "COMPLETED",
      "sub_status": "BOARDING_PASS_AVAILABLE",
      "checkin_message": "Checkin completed and boarding passes are available",
      "missing_info": [],
      "boarding_passes": [
        "https://files.example.com/boarding-pass.pdf"
      ],
      "scheduled_time": "2030-09-18T04:45:00.000Z",
      "created_at": "2030-09-16T10:00:00.000Z",
      "last_updated": "2030-09-18T05:00:00.000Z"
    }
  ],
  "pagination": {
    "page": 0,
    "limit": 25,
    "total": 1,
    "totalPages": 1
  }
}

Next action: Increment page while page + 1 is less than pagination.totalPages. Read departure_datetime as the origin's local clock even when it contains the legacy Z suffix. created_at, scheduled_time and last_updated are UTC instants.

Receive and verify webhooks

Include callbackData in your first subscribe request for a new booking. Retrying an active subscription does not add or change callback configuration; poll that existing attempt instead. callbackUrl and auth_header are required when callbackData is supplied; clientId and clientName are optional. Use a URL you control. The auth_header syntax is 'Authorization: Bearer <your-secret>' or 'X-API-Key: <your-secret>', with exactly one colon and no newline.

On your server, compare the configured header with your secret, save the event, and respond with 2xx within 10 seconds. Flyo does not add a body signature. Never place your Flyo incoming API key in public examples or expose callback secrets in logs.

Deduplicate event_id. Events can be repeated or arrive out of order. changes is a snapshot of status, sub_status, checkin_message, missing_info and boarding_passes; use status polling to reconcile uncertain ordering. Network errors, 5xx and 429 can be retried; other 4xx responses stop that event's delivery.

First subscription with a callback
curl -X POST "$FLYO_API_BASE_URL/extPartner/api/webcheckin/subscribe" \
  -H "X-API-Key: $FLYO_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "pnr": "ABC123",
  "flights": [
    {
      "airline": "6E",
      "flight_number": "6E203",
      "origin": "DEL",
      "destination": "BOM",
      "departure_datetime": "2030-09-20T10:00:00",
      "arrival_datetime": "2030-09-20T12:00:00"
    }
  ],
  "passengers": [
    {
      "first_name": "John",
      "last_name": "Doe",
      "email": "john@example.com"
    }
  ],
  "callbackData": {
    "callbackUrl": "https://partner.example.com/webhooks/flyo",
    "auth_header": "Authorization: Bearer replace-with-your-callback-secret"
  }
}'
Example event received by your server
{
  "event": "webcheckin.update",
  "event_id": "9f8d7e6c5b4a32109f8d7e6c5b4a32109f8d7e6c5b4a32109f8d7e6c5b4a3210",
  "occurredAt": "2030-09-18T05:00:00.000Z",
  "checkin_id": "CHK-783245",
  "changes": {
    "status": "COMPLETED",
    "sub_status": "BOARDING_PASS_AVAILABLE",
    "checkin_message": "Checkin completed and boarding passes are available",
    "missing_info": [],
    "boarding_passes": [
      "https://files.example.com/boarding-pass.pdf"
    ]
  }
}

Next action: Verify the configured header, save and deduplicate the event_id, acknowledge with 2xx, and process the status and boarding_passes snapshot.

Errors: what to do next

HTTP StatusMessage
400Fix missing fields, invalid JSON, invalid dates or document bindings; then retry the corrected payload.
401Check X-API-Key and whether the key is active. Do not retry the same invalid key in a loop.
402Check webcheckin entitlement and remaining quota in the dashboard. This can happen even on a duplicate subscribe.
404Check the identifier and the enterprise owning your API key.
409Poll the current attempt and inspect NOT_UPDATABLE or DUPLICATE_PNR. Do not repeatedly submit the same rejected update.
422Inspect error, message and optional reason_code. Correct a rejected journey or callback URL. For an update, check status: passenger changes may have committed before the scheduling rejection.
429Wait at least retryAfter seconds, then retry. Use webhooks or slower polling to reduce requests.
500 / timeoutCheck status or list requests before retrying a mutation. An error does not prove that no booking, attempt or passenger update was saved.

Getting Started

Ready to integrate?

Get your API key and start sending requests to the Flyo partner API.

Get your API key

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.

Dates and responses below are illustrative. Replace flight dates with your real future itinerary, at least 6 hours before departure, and replace every example identifier and file path. Never send the examples to production unchanged.

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. There is no fixed public base URL; your account manager will provide the host for your environment.

Every request must include a valid X-API-Key header. Obtain an 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.

JSON requests and responses are supported. Canonical subscribe and update also accept multipart/form-data for uploads. Flight departure_datetime is origin-airport local wall time; arrival_datetime is destination-airport local wall time. Supply YYYY-MM-DDTHH:mm:ss without an offset: a trailing Z or numeric offset is ignored, not converted. Airport IATA codes use three letters; airline IATA codes use two alphanumeric characters, such as AI or 6E.

Read departure_datetime as the origin airport's local clock and arrival_datetime as the destination airport's local clock. Do not preconvert flight times to UTC. DEL 2030-09-20T10:00:00 means 10:00 in Delhi (04:30 UTC); DXB 2030-09-20T12:00:00 means 12:00 in Dubai (08:00 UTC).

Use YYYY-MM-DDTHH:mm:ss (fractional seconds up to 3 digits are accepted). Ignore any Z or numeric offset suffix when interpreting a flight timestamp: 2030-09-20T10:00:00Z, 2030-09-20T10:00:00+05:30, 2030-09-20T10:00:00-04:00, and 2030-09-20T10:00:00-0400 all retain the local clock value 10:00. Prefer timestamps without suffixes to avoid ambiguity.

Validation rejects unknown airport timezones, invalid calendar dates, and nonexistent daylight-saving times. A repeated local time resolves to the earlier occurrence. Lifecycle fields such as scheduled_time, created_at, last_updated, and webhook occurredAt are actual UTC instants; departure_datetime in returned summaries preserves origin-local wall time with a legacy Z suffix.

These APIs are versionless. Use /extPartner/api/webcheckin/*. Legacy JSON subscribe, update, and status routes exist under /extPartner/webcheckin/*; there is no legacy requests route. Multipart uploads are supported only on canonical subscribe and update.

For coverage, integration timelines, and pricing, see the Web Check-in API overview.

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.

Use a dashboard-issued key for your integration. Keep it on your server, outside browser code and source control.

Validation rules: the header must be present and non-empty; it must match an active key; revoked, disabled, or unknown keys receive HTTP 401. There is no token expiry or refresh; a key stays active until it is revoked. In development environments only, a default environment key is accepted for testing. Production integrations must use a real dashboard-issued key.

Example
GET /extPartner/api/webcheckin/requests
X-API-Key: flyo_<issued-key>
Content-Type: application/json

Rate Limits

Allow for limits of 60 requests per minute and 1,000 per hour per API key. Poll at a sensible interval and use webhooks when possible. These limits are applied per server process.

When a limit is exceeded the API returns HTTP 429 with a retryAfter value in seconds. Wait at least that many seconds before retrying.

A new SCHEDULED subscription consumes one quota unit. ALREADY_SUBSCRIBED reuses an active attempt without another charge; REJECTED consumes no unit. Booking, attempt, and quota writes share a transaction, so transaction failures roll back the quota charge. Post-commit delivery or scheduling failures do not by themselves prove that no attempt was created; check existing requests before retrying.

Subscribe checks active entitlement and a positive remaining quota before duplicate detection. An exhausted, suspended, or missing entitlement can therefore return HTTP 402 even when retrying an existing active booking. Status, update, and requests do not require this subscribe entitlement check.

Error Format

Responses are JSON, but error shapes vary by handler. Many validation and business errors contain success: false, error, and message, as illustrated below. Authentication errors use human-readable error strings rather than a stable enum; some generic HTTP 500 responses may omit error. Journey rejections may include reason_code and details; do not assume those fields always exist. Inspect the HTTP status and fields actually returned.

Example
{
  "success": false,
  "error": "VALIDATION_ERROR",
  "message": "Missing or malformed request data"
}

Common Errors

HTTP StatusMessage
400VALIDATION_ERROR — missing or malformed request data.
401Missing, invalid, disabled, or revoked API key.
402NO_ENTITLEMENT, ENTITLEMENT_SUSPENDED, or QUOTA_EXHAUSTED — entitlement is missing, suspended, or has no remaining units.
404NOT_FOUND — the requested check-in or booking does not exist or belongs to another enterprise.
409Conflict — the resource cannot be modified in its current state.
422REJECTED — journey rule rejection such as departure too close, multi-airline or invalid one-way itinerary, or airline mismatch. The reason_code field may provide the machine-readable cause.
429Rate limit exceeded. retryAfter is returned in seconds.
500Unexpected server error; the error code is not guaranteed. Multipart parser and upload-limit failures may also use this status.

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.

For example, with 47 total records and a limit of 25, page 0 returns items 1-25 and page 1 returns items 26-47. The totalPages value is 2.

Example
{
  "success": true,
  "data": [],
  "pagination": {
    "page": 0,
    "limit": 25,
    "total": 47,
    "totalPages": 2
  }
}

Webhooks

Include callbackData in the first subscription for a new booking to receive status changes at your callbackUrl. Retrying an active subscription does not add or change callback configuration; continue polling if that attempt has no callback. Webhooks are sent for the event kind webcheckin.update whenever the check-in attempt changes state.

When callbackData is supplied, callbackUrl and auth_header are required. clientId and clientName are optional and fall back to the authenticated enterprise identity; uniqueness is not enforced. callbackUrl must parse as a URL. Use HTTPS for secure delivery; the validator does not enforce HTTPS.

auth_header must be in the format '<Header-Name>: <Header-Value>' and the header name must be either X-API-Key or Authorization. Use exactly one colon in auth_header; CR/LF and empty values are rejected. Flyo forwards the parsed header and value in every webhook request so your endpoint can verify it. Two valid examples are: X-API-Key: abc123 and Authorization: Bearer abc123.

The webhook payload includes event set to webcheckin.update, event_id (a SHA-256 hash of checkin_id, occurredAt, and event kind), occurredAt, checkin_id, and changes. The changes object is a snapshot of the current status, sub_status, checkin_message, missing_info, and boarding_passes. Treat event_id as opaque; separate events may report the same state.

Your callback should save the event and return 2xx within 10 seconds. Events can arrive more than once or out of order: deduplicate by event_id and poll status when you need the current state. Network failures, HTTP 5xx and HTTP 429 can be retried; other HTTP 4xx responses stop delivery for that event. Do not depend on a fixed retry schedule.

Flyo does not sign the webhook body or add a provider signature header. Authenticate the request using the auth_header value you configured.

Example
{
  "event": "webcheckin.update",
  "event_id": "9f8d7e6c5b4a32109f8d7e6c5b4a32109f8d7e6c5b4a32109f8d7e6c5b4a3210",
  "occurredAt": "2030-09-18T05:00:00.000Z",
  "checkin_id": "CHK-783245",
  "changes": {
    "status": "COMPLETED",
    "sub_status": "BOARDING_PASS_AVAILABLE",
    "checkin_message": "Checkin completed and boarding passes are available",
    "missing_info": [],
    "boarding_passes": [
      "https://files.example.com/boarding-pass.pdf"
    ]
  }
}
POST/extPartner/api/webcheckin/subscribe

Create Web Check-in Request

Authentication
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.

This endpoint is available on the canonical /extPartner/api/webcheckin/* surface. The legacy /extPartner/webcheckin/* route remains available for backward compatibility.

Missing contact, passport, or valid PNR details do not automatically reject the request; a non-empty passenger list and each passenger's first_name and last_name are still required. The attempt can be stored as SCHEDULED with a missing-information sub-status, allowing you to update the booking before automation runs.

Only one-way journeys are supported. Legs are sorted by departure instant, must connect end-to-end, cannot revisit an airport, and must share the same airline. Arrival, when provided, must be after departure when each airport timezone is applied.

Departure must be at least 6 hours away. A known airline without configured check-in timing is handled for manual fulfillment rather than rejected as unsupported; its partner-facing status is SCHEDULED. Scheduled automation is set to 15 minutes after the configured airline check-in window opens.

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.

Duplicate detection uses the authenticated partner, PNR and full first-leg local departure timestamp after journey ordering. The existing booking must use the same airline. Two departures at different times on the same date are distinct. An existing active matching attempt returns ALREADY_SUBSCRIBED without consuming another unit. An already completed attempt returns HTTP 422 REJECTED; failed or cancelled attempts can permit a new charged attempt, subject to validation and entitlement checks. Reusing the same partner, PNR, and full departure timestamp with another airline returns HTTP 422 with reason_code AIRLINE_MISMATCH.

Retry with the complete authoritative booking payload: subscribe upserts passenger and flight data before detecting an active duplicate. ALREADY_SUBSCRIBED reuses the attempt and avoids a second charge, but does not mean the booking payload was left unchanged.

HTTP 200 returns success: true with message SCHEDULED or ALREADY_SUBSCRIBED. Business rejections return HTTP 422 with error REJECTED; journey rejections include reason_code when available. An invalid callback URL instead returns HTTP 422 with error VALIDATION_ERROR.

Request

Headers
POST /extPartner/api/webcheckin/subscribe
X-API-Key: flyo_<issued-key>
Content-Type: application/json
cURL
curl -X POST "$FLYO_API_BASE_URL/extPartner/api/webcheckin/subscribe" \
  -H "X-API-Key: $FLYO_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "pnr": "ABC123",
  "flights": [
    {
      "airline": "AI",
      "flight_number": "AI302",
      "origin": "DEL",
      "destination": "DXB",
      "departure_datetime": "2030-09-20T10:00:00",
      "arrival_datetime": "2030-09-20T12:00:00"
    }
  ],
  "passengers": [
    {
      "first_name": "John",
      "last_name": "Doe",
      "email": "john@example.com",
      "phone": "9876543210",
      "country_code": "+91",
      "date_of_birth": "1995-07-20",
      "nationality": "IN",
      "country_of_residence": "IN",
      "passport": {
        "number": "N1234567",
        "date_of_issue": "2020-05-01",
        "expiry_date": "2035-05-01",
        "place_of_issue": "DELHI",
        "nationality": "IN"
      },
      "documents": [
        {
          "type": "VISA",
          "document_number": "V123456",
          "issuing_country": "AE",
          "expiry_date": "2035-05-01"
        }
      ],
      "seat_preference": {
        "row_preference": "rear",
        "column_preference": "window"
      }
    }
  ],
  "callbackData": {
    "callbackUrl": "https://partner.example.com/webhooks/flyo",
    "auth_header": "Authorization: Bearer <your-callback-secret>"
  }
}'

# With a passport upload
curl -X POST "$FLYO_API_BASE_URL/extPartner/api/webcheckin/subscribe" \
  -H "X-API-Key: $FLYO_API_KEY" \
  -F 'pnr=ABC123' \
  -F 'flights=[{"airline":"AI","flight_number":"AI302","origin":"DEL","destination":"DXB","departure_datetime":"2030-09-20T10:00:00","arrival_datetime":"2030-09-20T12:00:00"}]' \
  -F 'passengers=[{"first_name":"John","last_name":"Doe","email":"john@example.com","phone":"9876543210","country_code":"+91","date_of_birth":"1995-07-20","nationality":"IN","country_of_residence":"IN","passport":{"number":"N1234567","date_of_issue":"2020-05-01","expiry_date":"2035-05-01","place_of_issue":"DELHI","nationality":"IN","file_field":"traveller-passport"},"documents":[{"type":"VISA","document_number":"V123456","issuing_country":"AE","expiry_date":"2035-05-01","file_field":"traveller-visa"}],"seat_preference":{"row_preference":"rear","column_preference":"window"}}]' \
  -F 'traveller-passport=@/path/to/traveller-passport.pdf;type=application/pdf' \
  -F 'traveller-visa=@/path/to/traveller-visa.pdf;type=application/pdf'
Request Body
{
  "pnr": "ABC123",
  "flights": [
    {
      "airline": "AI",
      "flight_number": "AI302",
      "origin": "DEL",
      "destination": "DXB",
      "departure_datetime": "2030-09-20T10:00:00",
      "arrival_datetime": "2030-09-20T12:00:00"
    }
  ],
  "passengers": [
    {
      "first_name": "John",
      "last_name": "Doe",
      "email": "john@example.com",
      "phone": "9876543210",
      "country_code": "+91",
      "date_of_birth": "1995-07-20",
      "nationality": "IN",
      "country_of_residence": "IN",
      "passport": {
        "number": "N1234567",
        "date_of_issue": "2020-05-01",
        "expiry_date": "2035-05-01",
        "place_of_issue": "DELHI",
        "nationality": "IN"
      },
      "documents": [
        {
          "type": "VISA",
          "document_number": "V123456",
          "issuing_country": "AE",
          "expiry_date": "2035-05-01"
        }
      ],
      "seat_preference": {
        "row_preference": "rear",
        "column_preference": "window"
      }
    }
  ],
  "callbackData": {
    "callbackUrl": "https://partner.example.com/webhooks/flyo",
    "auth_header": "Authorization: Bearer <your-callback-secret>"
  }
}

Request Fields

FieldTypeRequiredDescription
pnrstringNoAirline record locator. Missing or invalid PNR is recorded as missing information, rather than a structural rejection.
flightsarrayYesOne-way connected itinerary operated by one airline. First departure must be at least six hours away.
flights[].airlinestringYesAirline IATA code; use two alphanumeric characters, for example AI or 6E.
flights[].flight_numberstringYesFlight number.
flights[].originstringYesOrigin IATA airport code; use three letters.
flights[].destinationstringYesDestination IATA airport code; use three letters.
flights[].departure_datetimestringYesOrigin-airport local wall clock. Prefer YYYY-MM-DDTHH:mm:ss without suffix. A supplied Z or numeric offset is ignored, never converted. Calendar and airport timezone validity are checked separately.
flights[].arrival_datetimestring | nullNoDestination-airport local wall clock. Prefer YYYY-MM-DDTHH:mm:ss without suffix. A supplied Z or numeric offset is ignored, never converted. Calendar and airport timezone validity are checked separately.
passengersarrayYesComplete passenger array. Updates replace the entire stored array; retain all authoritative passenger and document data.
passengers[].first_namestringYesFirst name.
passengers[].last_namestringYesLast name.
passengers[].emailstring | nullNoContact email. At least one valid passenger email is needed for readiness; malformed or absent email does not structurally reject subscribe.
passengers[].country_codestring | nullNoPhone country prefix, for example +91.
passengers[].phonestring | nullNoPhone number.
passengers[].date_of_birthstring | nullNoDate of birth; use YYYY-MM-DD.
passengers[].nationalitystring | nullNoNationality country code, for example IN.
passengers[].country_of_residencestring | nullNoResidence country code.
passengers[].passportobject | nullNoInternational readiness needs number, date_of_issue, expiry_date, place_of_issue and passport or passenger nationality for every passenger.
passengers[].passport.numberstring | nullNoPassport number.
passengers[].passport.date_of_issuestring | nullNoIssue date; use YYYY-MM-DD.
passengers[].passport.expiry_datestring | nullNoExpiry date; use YYYY-MM-DD.
passengers[].passport.place_of_issuestring | nullNoPlace of issue.
passengers[].passport.nationalitystring | nullNoNationality country code; passenger nationality is a readiness fallback.
passengers[].passport.document_urlstring | nullNoExisting passport document URL.
passengers[].passport.file_fieldstringNoExact arbitrary multipart file-part name to bind this scan. A scan does not replace passport metadata.
passengers[].documentsarray | nullNoSupporting documents.
passengers[].documents[].typeenum: VISA | IQAMA | PR_CARD | GREEN_CARDYesSupporting document type.
passengers[].documents[].document_numberstring | nullNoDocument number.
passengers[].documents[].issuing_countrystring | nullNoIssuing country code.
passengers[].documents[].expiry_datestring | nullNoExpiry date; use YYYY-MM-DD.
passengers[].documents[].document_urlstring | nullNoExisting document URL.
passengers[].documents[].file_fieldstringNoExact arbitrary multipart file-part name for this document.
passengers[].seat_preferenceobject | nullNoPassenger seat preferences.
passengers[].seat_preference.row_preferenceenum: front | middle | rear | nullNoPreferred cabin row.
passengers[].seat_preference.column_preferenceenum: window | middle | aisle | nullNoPreferred seat column.
callbackDataobject | nullNoOptional callback configuration. callbackUrl and auth_header are required when supplied.
callbackData.clientIdstringNoOptional; defaults to authenticated enterprise identity.
callbackData.clientNamestringNoOptional; defaults to authenticated enterprise identity.
callbackData.callbackUrlstringYesCallback URL. Use HTTPS for secure delivery; HTTPS is guidance, not an enforced restriction.
callbackData.auth_headerstringYesExactly one colon: X-API-Key: value or Authorization: Bearer value. Header names are case-insensitive. Empty values and CR/LF are rejected.

If callbackData is provided, callbackUrl and auth_header are required.

For multipart/form-data, JSON-stringify flights, passengers, and callbackData. Let curl or your HTTP client set the multipart boundary; do not manually set Content-Type. Passport uploads require passengers[].passport.file_field; supporting uploads use passengers[].documents[].file_field. Field names are arbitrary but must match the uploaded part exactly.

International passport completeness requires number, date_of_issue, expiry_date, place_of_issue, and nationality (falling back to passenger nationality). A passport image alone is insufficient. Missing names or an empty passenger list fail validation; incomplete automation details can instead produce missing_info.

auth_header must use X-API-Key or Authorization as the header name.

Subscribe uploads accept MIME types application/pdf and image/*, with up to 30 files per request and 10 MiB (10 × 1024 × 1024 bytes) per file. Unsupported MIME types are ignored; upload-limit or multipart-parser failures may return HTTP 500, not a guaranteed 413.

Response

HTTP 200 message is SCHEDULED or ALREADY_SUBSCRIBED. The quota object is optional and returned when a new attempt is scheduled and quota information is available.

Response
{
  "success": true,
  "message": "SCHEDULED",
  "booking_id": 123,
  "checkin_id": "CHK-783245",
  "status": "SCHEDULED",
  "sub_status": "COMPLETE_INFO",
  "missing_info": [],
  "status_message": "Check-in scheduled",
  "quota": {
    "included_units": 100,
    "consumed_units": 1
  }
}

Response Fields

FieldTypeDescription
successbooleanOperation succeeded.
messageenum: SCHEDULED | ALREADY_SUBSCRIBEDA new subscription or reuse of an active attempt.
booking_idintegerBooking identifier.
checkin_idstringCheck-in identifier.
statusenum: SCHEDULED | IN_PROGRESS | COMPLETED | FAILED | CANCELLEDNormalized partner-facing status.
sub_statusstringDetailed status.
missing_infoarrayMissing information needed before check-in can proceed.
missing_info[].typestringMissing-information code, for example MISSING_EMAIL or MISSING_PASSPORT.
status_messagestringHuman-readable explanation.
quotaobjectquota value.
quota.included_unitsintegerIncluded entitlement units.
quota.consumed_unitsintegerConsumed entitlement units.

Errors

HTTP StatusMessage
400VALIDATION_ERROR — missing or malformed request data.
401Missing, invalid, disabled, or revoked API key.
402NO_ENTITLEMENT, ENTITLEMENT_SUSPENDED, or QUOTA_EXHAUSTED — entitlement is missing, suspended, or exhausted.
422VALIDATION_ERROR — callbackUrl is not a valid URL.
422REJECTED — journey rule rejection, such as departure too close, multi-airline or invalid one-way itinerary, or airline mismatch. reason_code is provided for journey-rule failures when available.
429Rate limit exceeded. retryAfter is returned in seconds.
POST/extPartner/api/webcheckin/update

Update Web Check-in Request

Authentication
X-API-Key: flyo_<issued-key>

Updates an existing booking or its passenger list before automation runs. Requires an active API key and either a checkin_id or booking_id belonging to the enterprise.

Updates an existing web-check-in booking. The canonical external surface is /extPartner/api/webcheckin/update. The legacy /extPartner/webcheckin/* route remains available for backward compatibility.

Supported update types are passengers and pnr. The passengers update is a full replacement: you must resend the complete passenger list every time, including unchanged data. Omitting a field such as email removes the previous value. The API does not merge the payload into the existing record.

Documents can be attached to passengers during a passengers update. Passport scans and supporting documents such as visa, IQAMA, PR card, or green card may be uploaded. Accepted MIME types are application/pdf and image/*. Limits are 30 files per request and 10 MiB (10 × 1024 × 1024 bytes) per file. Unsupported MIME types are ignored; upload-limit or multipart-parser failures may return HTTP 500, not a guaranteed 413.

A passengers update that fills previously missing information can resume an eligible attempt and may trigger automation immediately if the check-in window is open. PNR updates refresh missing_info but do not reschedule or trigger automation; only the passengers update invokes the resume flow.

An update can return HTTP 422 REJECTED with reason_code DEPARTURE_TOO_CLOSE when completing the passenger information less than 6 hours before departure. Passenger changes have already been saved at this point. Poll status to inspect the latest attempt; do not assume the update rolled back.

Update eligibility uses internal states: SCHEDULED or FAILED with MISSING_INFO, or a booking with no attempt. Public states are normalized: internal FAILED/MISSING_INFO is returned as IN_PROGRESS/MISSING_INFO, while internal MANUAL_INTERVENTION_REQUIRED is returned as SCHEDULED but is not updateable. Do not infer eligibility from public status alone; other internal states return HTTP 409 NOT_UPDATABLE.

Request

Headers
POST /extPartner/api/webcheckin/update
X-API-Key: flyo_<issued-key>
Content-Type: application/json
cURL
curl -X POST "$FLYO_API_BASE_URL/extPartner/api/webcheckin/update" \
  -H "X-API-Key: $FLYO_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "checkin_id": "CHK-783245",
  "type": "passengers",
  "passengers": [
    {
      "first_name": "John",
      "last_name": "Doe",
      "email": "john@example.com",
      "phone": "9876543210",
      "country_code": "+91",
      "date_of_birth": "1995-07-20",
      "nationality": "IN",
      "country_of_residence": "IN",
      "passport": {
        "number": "N1234567",
        "date_of_issue": "2020-05-01",
        "expiry_date": "2035-05-01",
        "place_of_issue": "DELHI",
        "nationality": "IN"
      },
      "documents": [
        {
          "type": "VISA",
          "document_number": "V123456",
          "issuing_country": "AE",
          "expiry_date": "2035-05-01"
        }
      ],
      "seat_preference": {
        "row_preference": "rear",
        "column_preference": "window"
      }
    }
  ]
}'
Request Body
{
  "checkin_id": "CHK-783245",
  "type": "passengers",
  "passengers": [
    {
      "first_name": "John",
      "last_name": "Doe",
      "email": "john@example.com",
      "phone": "9876543210",
      "country_code": "+91",
      "date_of_birth": "1995-07-20",
      "nationality": "IN",
      "country_of_residence": "IN",
      "passport": {
        "number": "N1234567",
        "date_of_issue": "2020-05-01",
        "expiry_date": "2035-05-01",
        "place_of_issue": "DELHI",
        "nationality": "IN"
      },
      "documents": [
        {
          "type": "VISA",
          "document_number": "V123456",
          "issuing_country": "AE",
          "expiry_date": "2035-05-01"
        }
      ],
      "seat_preference": {
        "row_preference": "rear",
        "column_preference": "window"
      }
    }
  ]
}

Request Fields

FieldTypeRequiredDescription
checkin_idstringNoCheck-in identifier. Takes precedence over booking_id.
webcheckin_idstringNoCompatibility alias for checkin_id.
booking_idinteger | stringNoBooking identifier; usable without uploads. Uploads require checkin_id or webcheckin_id.
typeenum: passengers | pnrNoUpdate type. Can be omitted when top-level passengers is supplied.
operationenum: updateNoOnly update is supported; defaults to update.
passengersarrayNoComplete passenger array. Updates replace the entire stored array; retain all authoritative passenger and document data.
passengers[].first_namestringYesFirst name.
passengers[].last_namestringYesLast name.
passengers[].emailstring | nullNoContact email. At least one valid passenger email is needed for readiness; malformed or absent email does not structurally reject subscribe.
passengers[].country_codestring | nullNoPhone country prefix, for example +91.
passengers[].phonestring | nullNoPhone number.
passengers[].date_of_birthstring | nullNoDate of birth; use YYYY-MM-DD.
passengers[].nationalitystring | nullNoNationality country code, for example IN.
passengers[].country_of_residencestring | nullNoResidence country code.
passengers[].passportobject | nullNoInternational readiness needs number, date_of_issue, expiry_date, place_of_issue and passport or passenger nationality for every passenger.
passengers[].passport.numberstring | nullNoPassport number.
passengers[].passport.date_of_issuestring | nullNoIssue date; use YYYY-MM-DD.
passengers[].passport.expiry_datestring | nullNoExpiry date; use YYYY-MM-DD.
passengers[].passport.place_of_issuestring | nullNoPlace of issue.
passengers[].passport.nationalitystring | nullNoNationality country code; passenger nationality is a readiness fallback.
passengers[].passport.document_urlstring | nullNoExisting passport document URL.
passengers[].passport.file_fieldstringNoExact arbitrary multipart file-part name to bind this scan. A scan does not replace passport metadata.
passengers[].documentsarray | nullNoSupporting documents.
passengers[].documents[].typeenum: VISA | IQAMA | PR_CARD | GREEN_CARDYesSupporting document type.
passengers[].documents[].document_numberstring | nullNoDocument number.
passengers[].documents[].issuing_countrystring | nullNoIssuing country code.
passengers[].documents[].expiry_datestring | nullNoExpiry date; use YYYY-MM-DD.
passengers[].documents[].document_urlstring | nullNoExisting document URL.
passengers[].documents[].file_fieldstringNoExact arbitrary multipart file-part name for this document.
passengers[].seat_preferenceobject | nullNoPassenger seat preferences.
passengers[].seat_preference.row_preferenceenum: front | middle | rear | nullNoPreferred cabin row.
passengers[].seat_preference.column_preferenceenum: window | middle | aisle | nullNoPreferred seat column.
payloadobjectNopayload value.
payload.passengersarrayNoComplete passenger array. Updates replace the entire stored array; retain all authoritative passenger and document data.
payload.passengers[].first_namestringYesFirst name.
payload.passengers[].last_namestringYesLast name.
payload.passengers[].emailstring | nullNoContact email. At least one valid passenger email is needed for readiness; malformed or absent email does not structurally reject subscribe.
payload.passengers[].country_codestring | nullNoPhone country prefix, for example +91.
payload.passengers[].phonestring | nullNoPhone number.
payload.passengers[].date_of_birthstring | nullNoDate of birth; use YYYY-MM-DD.
payload.passengers[].nationalitystring | nullNoNationality country code, for example IN.
payload.passengers[].country_of_residencestring | nullNoResidence country code.
payload.passengers[].passportobject | nullNoInternational readiness needs number, date_of_issue, expiry_date, place_of_issue and passport or passenger nationality for every passenger.
payload.passengers[].passport.numberstring | nullNoPassport number.
payload.passengers[].passport.date_of_issuestring | nullNoIssue date; use YYYY-MM-DD.
payload.passengers[].passport.expiry_datestring | nullNoExpiry date; use YYYY-MM-DD.
payload.passengers[].passport.place_of_issuestring | nullNoPlace of issue.
payload.passengers[].passport.nationalitystring | nullNoNationality country code; passenger nationality is a readiness fallback.
payload.passengers[].passport.document_urlstring | nullNoExisting passport document URL.
payload.passengers[].passport.file_fieldstringNoExact arbitrary multipart file-part name to bind this scan. A scan does not replace passport metadata.
payload.passengers[].documentsarray | nullNoSupporting documents.
payload.passengers[].documents[].typeenum: VISA | IQAMA | PR_CARD | GREEN_CARDYesSupporting document type.
payload.passengers[].documents[].document_numberstring | nullNoDocument number.
payload.passengers[].documents[].issuing_countrystring | nullNoIssuing country code.
payload.passengers[].documents[].expiry_datestring | nullNoExpiry date; use YYYY-MM-DD.
payload.passengers[].documents[].document_urlstring | nullNoExisting document URL.
payload.passengers[].documents[].file_fieldstringNoExact arbitrary multipart file-part name for this document.
payload.passengers[].seat_preferenceobject | nullNoPassenger seat preferences.
payload.passengers[].seat_preference.row_preferenceenum: front | middle | rear | nullNoPreferred cabin row.
payload.passengers[].seat_preference.column_preferenceenum: window | middle | aisle | nullNoPreferred seat column.
payload.pnrstringNoNew nonempty PNR; required for type pnr. Top-level pnr is not read.

Send the request as multipart/form-data when uploading files. JSON-only updates without files can still use application/json.

JSON-stringify passengers (or payload) as a multipart text field. Set passport.file_field or documents[].file_field to the matching arbitrary file-part name; a file named passport-0 alone is not bound automatically. Let the client generate the multipart Content-Type boundary.

Uploads require checkin_id (or compatibility alias webcheckin_id); booking_id alone is insufficient when files are attached. Without uploads, either identifier works. If both identifiers are supplied, checkin_id takes precedence.

PNR update JSON example: {"checkin_id":"CHK-783245","type":"pnr","payload":{"pnr":"DEF456"}}. operation defaults to update. type may be omitted only when top-level passengers lets the controller infer a passengers update.

Response

Returns the refreshed check-in attempt when one exists, for either update type. If the booking has no attempt, data contains only booking_id.

Response
{
  "success": true,
  "type": "passengers",
  "operation": "update",
  "data": {
    "checkin_id": "CHK-783245",
    "booking_id": 123,
    "status": "SCHEDULED",
    "sub_status": "COMPLETE_INFO",
    "checkin_message": "Check-in scheduled",
    "missing_info": [],
    "boarding_passes": [],
    "last_updated": "2030-09-16T10:30:00.000Z"
  }
}

Response Fields

FieldTypeDescription
successbooleanOperation succeeded.
typeenum: passengers | pnrUpdate type. Can be omitted when top-level passengers is supplied.
operationstringoperation value.
dataobjectAttempt status, or booking_id when no attempt exists.

Errors

HTTP StatusMessage
400VALIDATION_ERROR — missing or malformed request data.
401Missing, invalid, disabled, or revoked API key.
404The check-in or booking does not exist or belongs to another enterprise.
409NOT_UPDATABLE — the check-in can no longer be modified in its current state.
409DUPLICATE_PNR — another booking for this partner already uses the supplied PNR.
422REJECTED / DEPARTURE_TOO_CLOSE — a completed passenger update is saved before the six-hour scheduling check rejects resumption. Poll status before deciding what to do next.
500Unexpected error or multipart upload failure. Check status before retrying an update.
429Rate limit exceeded. retryAfter is returned in seconds.
GET/extPartner/api/webcheckin/status?checkin_id=CHK-...

Get Web Check-in Status

Authentication
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.

COMPLETED does not guarantee a boarding pass is ready. Show a download only when boarding_passes contains URLs; BOARDING_PASS_NOT_AVAILABLE means check-in completed without an available pass. Continue checking status or receiving updates.

Request

Headers
GET /extPartner/api/webcheckin/status?checkin_id=CHK-783245
X-API-Key: flyo_<issued-key>
cURL
curl -X GET "$FLYO_API_BASE_URL/extPartner/api/webcheckin/status?checkin_id=CHK-783245" \
  -H "X-API-Key: $FLYO_API_KEY"

Request Fields

FieldTypeRequiredDescription
checkin_idstringYesCheck-in identifier; checkinId compatibility alias is also accepted.

Response

Response
{
  "success": true,
  "checkin_id": "CHK-783245",
  "booking_id": 123,
  "status": "COMPLETED",
  "sub_status": "BOARDING_PASS_AVAILABLE",
  "checkin_message": "Checkin completed and boarding passes are available",
  "missing_info": [],
  "boarding_passes": [
    "https://files.example.com/boarding-pass.pdf"
  ],
  "last_updated": "2030-09-18T05:00:00.000Z"
}

Response Fields

FieldTypeDescription
successbooleanOperation succeeded.
checkin_idstringPublic check-in identifier.
booking_idintegerBooking identifier.
statusenum: SCHEDULED | IN_PROGRESS | COMPLETED | FAILED | CANCELLEDNormalized partner-facing status.
sub_statusstringDetailed status; may be empty or free-form.
checkin_messagestringHuman-readable explanation.
missing_infoarrayMissing information needed before check-in can proceed.
missing_info[].typestringMissing-information code, for example MISSING_EMAIL or MISSING_PASSPORT.
boarding_passesarrayBoarding-pass URLs. COMPLETED can still have an empty array; inspect sub_status and this array.
last_updatedUTC timestampLatest update as a UTC instant.

Errors

HTTP StatusMessage
400checkin_id is missing.
401Missing, invalid, disabled, or revoked API key.
404The check-in does not exist or belongs to another enterprise.
429Rate limit exceeded. retryAfter is returned in seconds.
GET/extPartner/api/webcheckin/requests?page=0&limit=25&status=COMPLETED

List Enterprise Check-in Requests

Authentication
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.

Results are ordered by created_at descending. 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.

Use integer page and limit values. Missing, nonnumeric, or negative page becomes 0. Missing, nonnumeric, or zero limit becomes 25; negative limits clamp to 1. Fractional values are not explicitly validated, so do not rely on a 400 response for malformed pagination.

Request

Headers
GET /extPartner/api/webcheckin/requests?page=0&limit=25&status=COMPLETED
X-API-Key: flyo_<issued-key>
cURL
curl -X GET "$FLYO_API_BASE_URL/extPartner/api/webcheckin/requests?page=0&limit=25&status=COMPLETED" \
  -H "X-API-Key: $FLYO_API_KEY"

Request Fields

FieldTypeRequiredDescription
pagestringNoUse a zero-based integer; invalid or negative input falls back to 0.
limitstringNoUse an integer; defaults to 25 and clamps to 1–100.
statusstringNoOptional normalized status filter. Unknown values are ignored.

Response

Response
{
  "success": true,
  "data": [
    {
      "checkin_id": "CHK-783245",
      "booking_id": 123,
      "pnr": "ABC123",
      "origin": "DEL",
      "destination": "DXB",
      "departure_datetime": "2030-09-20T10:00:00.000Z",
      "airline": "AI",
      "flight_number": "AI302",
      "status": "COMPLETED",
      "sub_status": "BOARDING_PASS_AVAILABLE",
      "checkin_message": "Checkin completed and boarding passes are available",
      "missing_info": [],
      "boarding_passes": [
        "https://files.example.com/boarding-pass.pdf"
      ],
      "scheduled_time": "2030-09-18T04:45:00.000Z",
      "created_at": "2030-09-16T10:00:00.000Z",
      "last_updated": "2030-09-18T05:00:00.000Z"
    }
  ],
  "pagination": {
    "page": 0,
    "limit": 25,
    "total": 1,
    "totalPages": 1
  }
}

Response Fields

FieldTypeDescription
successbooleanOperation succeeded.
dataarrayEnterprise-scoped request summaries.
data[].checkin_idstringPublic check-in identifier.
data[].booking_idintegerBooking identifier.
data[].statusenum: SCHEDULED | IN_PROGRESS | COMPLETED | FAILED | CANCELLEDNormalized partner-facing status.
data[].sub_statusstringDetailed status; may be empty or free-form.
data[].checkin_messagestringHuman-readable explanation.
data[].missing_infoarrayMissing information needed before check-in can proceed.
data[].missing_info[].typestringMissing-information code, for example MISSING_EMAIL or MISSING_PASSPORT.
data[].boarding_passesarrayBoarding-pass URLs. COMPLETED can still have an empty array; inspect sub_status and this array.
data[].last_updatedUTC timestampLatest update as a UTC instant.
data[].pnrstring | nullAirline record locator.
data[].originstring | nullOrigin IATA airport code.
data[].destinationstring | nullDestination IATA airport code.
data[].departure_datetimestring | nullOrigin-local departure wall clock serialized with a legacy Z suffix. Do not treat this suffix as UTC.
data[].airlinestring | nullAirline IATA code.
data[].flight_numberstring | nullFlight number.
data[].scheduled_timeUTC timestampScheduled automation time as a UTC instant, or null.
data[].created_atUTC timestampCreation as a UTC instant.
paginationobjectpagination value.
pagination.pageintegerZero-based page.
pagination.limitintegerApplied page size.
pagination.totalintegerMatching items.
pagination.totalPagesintegerTotal pages.

Errors

HTTP StatusMessage
401Missing, invalid, disabled, or revoked API key.
429Rate limit exceeded. retryAfter is returned in seconds.