Reference

API Reference

The Bluecrest partner API lets you push flight disruptions from your DCS, receive real-time webhook events as passengers self-serve, and query claim status programmatically. All endpoints live under https://api.bluecrestlab.com and require an X-API-Key header.

Overview

Base URL

https://api.bluecrestlab.com

Authentication

Pass your API key in every request as an X-API-Key header — not Authorization: Bearer. Sandbox keys are prefixed wp_sandbox_. Live keys use wp_live_. Register via the portal UI or call POST /v1/dev/register with your email and company name to self-issue a sandbox key programmatically.

Idempotency

All POST requests accept an idempotency_key field. Submitting the same key twice returns the original response without creating a duplicate — safe to retry on network failure.

# Include this header on every request
X-API-Key: wp_sandbox_xxxxxxxxxxxxxxxxxxxxxxxx

# Example authenticated request
curl https://api.bluecrestlab.com/v1/partner/airline/disruptions \
  -H "X-API-Key: wp_sandbox_xxxx…" \
  -H "Content-Type: application/json"

Integration patterns

Choose the pattern that matches how your systems generate disruption data.

A

Airline Direct

GA
/v1/partner/airline/*

Your DCS pushes a disruption manifest to Bluecrest. Passengers are notified automatically and self-serve via the claim portal.

POST /v1/partner/airline/disruptions — push the event
Bluecrest notifies passengers via SMS / email
Receive case.* webhooks as passengers self-serve

Best for airlines with a DCS that can make outbound HTTPS calls.

B

Kiosk

GA
/v1/partner/kiosk/*

Passengers initiate a claim themselves by scanning their boarding pass at an airport kiosk or via the web portal. No API call needed from your side.

Passenger submits via branded portal or OCR kiosk
Bluecrest verifies boarding pass + disruption
Receive case.* webhooks as cases progress

Best for airlines without DCS integration, or as a fallback channel.

C

Booking Platform

Coming soon
/v1/partner/booking/*

OTAs and booking platforms (Go7, Amadeus, Sabre) can submit disruptions on behalf of their airline partners and receive consolidated reporting across carriers.

Platform authenticates with a multi-airline partner key
POST disruptions per airline_id
Receive webhooks scoped by airline or platform-wide

Reach out to discuss early access.

All patterns converge on the same webhook stream. Regardless of how a case is created, you receive the same case.* events and can query status with GET /v1/partner/claims/{claim_id}.

Submit disruption

POST/v1/partner/airline/disruptions
Push a flight disruption from your DCS. Bluecrest ingests the passenger manifest and returns each passenger echoed back with their passenger_id. Use those IDs in all subsequent compensation and rerouting calls for this disruption. Use an idempotency_key based on flight + date + type to safely retry on network failure without creating duplicates.

The response includes a portal_url — a branded passenger self-service link for this disruption. Passengers can use it to submit their own claim if the airline does not complete rerouting on their behalf. Any claims submitted via the portal generate case.created events on your webhook.

Parameters

ParameterTypeRequiredDescription
flight_numberstringrequiredIATA flight code (e.g. NK001)
flight_datestringrequiredISO date YYYY-MM-DD
origin_iatastringrequired3-letter IATA origin airport
destination_iatastringrequired3-letter IATA destination airport
disruption_typestringrequired"CANCELLED" | "DELAYED" | "DIVERTED"
scheduled_departurestringrequiredISO 8601 datetime (UTC)
idempotency_keystringrequiredUnique key per disruption — format: {flight}-{date}-{type}
passengers[].passenger_idstringrequiredYour stable ID for this passenger (max 64 chars, alphanumeric + hyphens recommended) — scoped to your tenant, echoed back, used in all subsequent calls
passengers[].pnrstringrequiredBooking reference (5–8 chars)
passengers[].last_namestringrequiredPassenger last name (uppercase)
passengers[].first_namestringrequiredPassenger first name
passengers[].cabin_classstringrequired"ECONOMY" | "PREMIUM_ECONOMY" | "BUSINESS" | "FIRST"
passengers[].ticket_numberstringoptional13-digit IATA ticket number
passengers[].seat_numberstringoptionalSeat assignment (e.g. 14A)
passengers[].nationalitystringoptionalISO 3166-1 alpha-3 country code (e.g. GBR)
delay_minutesintegeroptionalGate-to-gate delay in minutes — required when disruption_type = "DELAYED" (e.g. 185)
actual_departurestringoptionalActual gate departure UTC ISO 8601 — null if cancelled
source_systemstringoptionalOriginating system identifier for audit purposes (default: "AIRLINE_DCS")
curl -X POST https://api.bluecrestlab.com/v1/partner/airline/disruptions \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "flight_number": "NK001",
    "flight_date": "2026-05-01",
    "origin_iata": "ARN",
    "destination_iata": "LHR",
    "disruption_type": "CANCELLED",
    "scheduled_departure": "2026-05-01T08:30:00Z",
    "idempotency_key": "NK001-20260501-CANCELLED",
    "passengers": [
      {
        "passenger_id": "NA-PAX-001",
        "pnr": "NK1234",
        "last_name": "SMITH",
        "first_name": "John",
        "cabin_class": "ECONOMY"
      },
      {
        "passenger_id": "NA-PAX-002",
        "pnr": "NK1235",
        "last_name": "JONES",
        "first_name": "Sarah",
        "cabin_class": "BUSINESS"
      }
    ]
  }'
Response201 Created
{
  "disruption_id": "f800450b-20f5-4382-895c-9ecdef8ff5de",
  "status": "PROCESSED",
  "flight_number": "NK001",
  "flight_date": "2026-05-01",
  "disruption_type": "CANCELLED",
  "passenger_count": 2,
  "passengers": [
    { "passenger_id": "NA-PAX-001", "pnr": "NK1234" },
    { "passenger_id": "NA-PAX-002", "pnr": "NK1235" }
  ],
  "portal_url": "https://claim.bluecrestlab.com/nk001-2026-05-01",
  "idempotency_key": "NK001-20260501-CANCELLED",
  "created_at": "2026-05-01T06:00:00Z"
}

Idempotency

Always set idempotency_key to a value unique per disruption event — e.g. NK001-20260501-CANCELLED. Re-submitting the same key within 24 hours returns the original 201 response and does not create a duplicate disruption. Submitting the same key with different parameters returns 409.

Safe retry rules

RETRY5xx / network timeoutRetry with the same idempotency_key
RETRY429 Rate limitedBack off and retry after a short delay
RETRY409 ConflictAlready accepted — treat as success
STOP4xx (other)Do not retry — fix the request first

Get disruption status

GET/v1/partner/airline/disruptions/{disruption_id}
Returns the current processing state of a disruption event. The POST /disruptions response already includes a status field — call this endpoint if you need to re-check state later or poll until PROCESSED before making per-passenger calls.

In the current sandbox, ingestion is synchronous: the POST response returns status: "PROCESSED" immediately and processed_count equals passenger_count. No polling loop is required.

Parameters

ParameterTypeRequiredDescription
disruption_idUUID (string, path)requireddisruption_id from POST /disruptions response
curl "https://api.bluecrestlab.com/v1/partner/airline/disruptions/{disruption_id}" \
  -H "X-API-Key: YOUR_API_KEY"
Response200 OK
{
  "disruption_id": "f800450b-20f5-4382-895c-9ecdef8ff5de",
  "status": "PROCESSED",
  "flight_number": "NK001",
  "flight_date": "2026-05-01",
  "origin_iata": "ARN",
  "destination_iata": "LHR",
  "disruption_type": "CANCELLED",
  "delay_minutes": null,
  "passenger_count": 2,
  "processed_count": 2,
  "created_at": "2026-05-01T06:00:00Z",
  "updated_at": "2026-05-01T06:00:00Z"
}

Get compensation eligibility

GET/v1/partner/airline/disruptions/{disruption_id}/passengers/{passenger_id}/compensation
Returns EC 261/2004 (or applicable regulation) eligibility for a single passenger. Use the disruption_id from the disruption create response and the passenger_id you submitted in the manifest. If you prefer passengers to self-serve their claim, share the portal_url from the POST /disruptions response instead — they will complete the flow via the branded portal and you will receive a case.created webhook.

Parameters

ParameterTypeRequiredDescription
disruption_idstring (path)requireddisruption_id from POST /disruptions response
passenger_idstring (path)requiredpassenger_id you submitted in the manifest
curl "https://api.bluecrestlab.com/v1/partner/airline/disruptions/{disruption_id}/passengers/{passenger_id}/compensation" \
  -H "X-API-Key: YOUR_API_KEY"
Response200 OK
{
  "disruption_id": "f800450b-20f5-4382-895c-9ecdef8ff5de",
  "passenger_id": "NA-PAX-001",
  "pnr": "NK1234",
  "eligible": true,
  "regulation": "EC261/2004",
  "compensation_tier": "TIER_3",
  "compensation_amount_eur": 600.0,
  "currency": "EUR",
  "eligibility_reason": "Flight distance ARN–LHR exceeds 3500 km and cancellation notified fewer than 14 days before departure.",
  "exclusions": [],
  "status": "ELIGIBLE"
}

Get rerouting options

GET/v1/partner/airline/disruptions/{disruption_id}/passengers/{passenger_id}/rerouting
Returns up to 5 ranked alternative itineraries for the passenger. Each option includes a booking_token and a booking_token_expires_at UTC timestamp — the token is valid for 30 minutes from generated_at. If the token expires before the passenger selects, call this endpoint again — the response always contains a fresh set of tokens. Options are ranked by earliest arrival, cabin-class parity with the original booking, and live seat availability. Business and premium passengers are offered cabin-equivalent alternatives first; downgrades appear at the bottom of the list.

Parameters

ParameterTypeRequiredDescription
disruption_idstring (path)requireddisruption_id from POST /disruptions response
passenger_idstring (path)requiredpassenger_id you submitted in the manifest
curl "https://api.bluecrestlab.com/v1/partner/airline/disruptions/{disruption_id}/passengers/{passenger_id}/rerouting" \
  -H "X-API-Key: YOUR_API_KEY"
Response200 OK
{
  "disruption_id": "f800450b-20f5-4382-895c-9ecdef8ff5de",
  "passenger_id": "NA-PAX-001",
  "pnr": "NK1234",
  "origin_iata": "ARN",
  "destination_iata": "LHR",
  "generated_at": "2026-05-01T06:05:00Z",
  "options": [
    {
      "option_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "rank": 1,
      "mode": "FLIGHT",
      "provider": "BLUECREST",
      "carrier": "AA",
      "carrier_name": "American Airlines",
      "service_number": "AA100",
      "departure_at": "2026-05-02T08:00:00Z",
      "arrival_at": "2026-05-02T11:30:00Z",
      "origin_iata": "ARN",
      "destination_iata": "LHR",
      "cabin_class": "ECONOMY",
      "stops": 0,
      "total_duration_minutes": 210,
      "score": 92,
      "booking_token": "bc_tok1_f800450b-20f5-4382-895c-9ecdef8ff5de_3c2d1e4f-…",
      "booking_token_expires_at": "2026-05-01T06:35:00Z"
    }
  ]
}

Select rerouting option

POST/v1/partner/airline/disruptions/{disruption_id}/passengers/{passenger_id}/rerouting/select
Confirms and books the chosen itinerary. Pass the option_id and booking_token from the rerouting options response. Returns 422 if the token has expired — call GET .../rerouting to refresh before retrying. The cost field in the response is the fare charged to the airline by the operating carrier. 0.0 indicates the carrier operates the replacement service themselves; non-zero amounts are invoiced to the airline separately and do not appear on the passenger's ticket.

Parameters

ParameterTypeRequiredDescription
disruption_idstring (path)requireddisruption_id from POST /disruptions response
passenger_idstring (path)requiredpassenger_id you submitted in the manifest
option_idUUID (string)requiredoption_id from GET .../rerouting response — must be a valid UUID v4
booking_tokenstringrequiredbooking_token from the chosen option — expires 30 min after generation
curl -X POST "https://api.bluecrestlab.com/v1/partner/airline/disruptions/{disruption_id}/passengers/{passenger_id}/rerouting/select" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "option_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "booking_token": "bc_tok1_f800450b-20f5-4382-895c-9ecdef8ff5de_3c2d1e4f-…"
  }'
Response200 OK
{
  "disruption_id": "f800450b-20f5-4382-895c-9ecdef8ff5de",
  "passenger_id": "NA-PAX-001",
  "option_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "booking_id": "7a3b9e2c-1d4f-5e6a-8b9c-0d1e2f3a4b5c",
  "provider_ref": "X7KM42",
  "state": "CONFIRMED",
  "booking_type": "flight",
  "mode": "FLIGHT",
  "carrier": "AA",
  "service_number": "AA100",
  "departure_at": "2026-05-02T08:00:00Z",
  "arrival_at": "2026-05-02T11:30:00Z",
  "cost": 0.0,
  "currency": "GBP",
  "confirmed_at": "2026-05-01T06:08:00Z"
}

Claim status

GET/v1/partner/claims/{claim_id}
Fetch the current state of a specific compensation claim. The claim_id is provided in the case.created webhook payload. States progress from SUBMITTEDUNDER_REVIEW APPROVED or REJECTED.

Parameters

ParameterTypeRequiredDescription
claim_idstring (path)requiredclaim_id from the case.created webhook payload
curl "https://api.bluecrestlab.com/v1/partner/claims/{claim_id}" \
  -H "X-API-Key: YOUR_API_KEY"
Response200 OK
{
  "claim_id": "cl_sandbox_001",
  "state": "APPROVED",
  "passenger_pnr": "NK1234",
  "flight_number": "NK001",
  "disruption_type": "CANCELLED",
  "amount_gbp": 350,
  "payout_method": "bank_transfer",
  "created_at": "2026-05-01T09:00:00Z",
  "updated_at": "2026-05-01T11:30:00Z"
}

Register webhook

POST/v1/partner/webhooks
Register a callback URL to receive real-time events as passengers move through the disruption flow. Every delivery is signed with HMAC-SHA256 so you can verify authenticity server-side. The secret field in the registration response is your signing secret — it is shown exactly once and cannot be retrieved again. Store it securely alongside your API key before making any other call.

To rotate a compromised secret, delete the webhook and re-register — a new secret is issued on each registration. There is no in-place rotation to avoid a gap in delivery coverage during the switchover.

Sandbox webhooks are catch-all — every event type is delivered to your registered URL regardless of which scenario is active. Per-event filtering is available in production.

Parameters

ParameterTypeRequiredDescription
urlstringrequiredHTTPS endpoint to receive events
descriptionstringoptionalHuman-readable label
curl -X POST https://api.bluecrestlab.com/v1/partner/webhooks \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourdomain.com/bluecrest/events",
    "description": "Production webhook"
  }'
Response200 OK
{
  "webhook_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "url": "https://yourdomain.com/bluecrest/events",
  "secret": "whsec_xxxxxxxxxxxxxxxxxx",
  "message": "Use the secret to verify webhook signatures via HMAC-SHA256."
}

Event types

disruption.ingestedDisruption manifest accepted — one event per POST /disruptions call, passengers array included (Airline Direct)
disruption.checkedPassenger checked in via kiosk — eligibility computed
evidence.confirmedBoarding pass or supporting evidence verified
case.createdCompensation claim created for a passenger
case.escalatedIssue escalated to airline staff
booking.flight_confirmedReplacement flight booking confirmed (Airline Direct)
booking.hotel_confirmedHotel accommodation booking confirmed
booking.transport_confirmedGround transport booking confirmed
compensation.resultCompensation payout processed — amount and method in payload
case.evidence_added(coming soon) Additional evidence added to an existing claim
case.approved(coming soon) Claim approved — payout initiated
case.rejected(coming soon) Claim rejected — reason included in payload
case.completed(coming soon) Full passenger journey resolved and closed

Example payloads

Every event is delivered as a POST to your registered URL with a JSON body. All payloads share the same envelope: event (event type string), event_id (unique delivery ID), created_at (ISO 8601 UTC), and data (event-specific object). Use X-Bluecrest-Delivery to deduplicate retries — store it and discard deliveries you have already processed. Respond with any 2xx status to acknowledge.

Granularity: disruption.ingested fires once per manifest — a single event containing all passengers, matching the POST /disruptions call that triggered it. All downstream events (booking.flight_confirmed, case.created, etc.) fire once per passenger as each action occurs.

# --- disruption.ingested (fires once per POST /disruptions call, not per passenger) ---
POST https://yourdomain.com/bluecrest/events
Content-Type: application/json
X-Bluecrest-Signature: 3d9f2c1a8e...
X-Bluecrest-Event: disruption.ingested
X-Bluecrest-Delivery: d1e2f3a4-b5c6-7890-abcd-ef1234567890

{
  "event": "disruption.ingested",
  "event_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "created_at": "2026-05-01T09:10:00Z",
  "data": {
    "disruption_id": "f800450b-20f5-4382-895c-9ecdef8ff5de",
    "flight_number": "NK001",
    "flight_date": "2026-05-01",
    "origin_iata": "ARN",
    "destination_iata": "LHR",
    "disruption_type": "CANCELLED",
    "passenger_count": 2,
    "passengers": [
      { "passenger_id": "NA-PAX-001", "pnr": "NK1234" },
      { "passenger_id": "NA-PAX-002", "pnr": "NK1235" }
    ]
  }
}

# --- booking.flight_confirmed (fires after POST .../rerouting/select — Airline Direct) ---
{
  "event": "booking.flight_confirmed",
  "event_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "created_at": "2026-05-01T09:11:00Z",
  "data": {
    "disruption_id": "f800450b-20f5-4382-895c-9ecdef8ff5de",
    "passenger_id": "NA-PAX-001",
    "booking_id": "7a3b9e2c-1d4f-5e6a-8b9c-0d1e2f3a4b5c",
    "option_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "carrier": "AA",
    "service_number": "AA100",
    "departure_at": "2026-05-02T08:00:00Z",
    "arrival_at": "2026-05-02T11:30:00Z",
    "provider_ref": "X7KM42",
    "state": "CONFIRMED"
  }
}

# --- case.created (fires when passenger completes claim portal) ---
{
  "event": "case.created",
  "event_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "created_at": "2026-05-01T09:12:34Z",
  "data": {
    "case_id": "cl_sandbox_001",
    "disruption_id": "f800450b-20f5-4382-895c-9ecdef8ff5de",
    "passenger_id": "NA-PAX-001",
    "pnr": "NK1234",
    "flight_number": "NK001",
    "flight_date": "2026-05-01",
    "disruption_type": "CANCELLED",
    "state": "SUBMITTED",
    "regulation": "EC261/2004",
    "compensation_eligible": true,
    "estimated_amount_eur": 600.0,
    "portal_url": "https://claim.bluecrestlab.com/nk001-2026-05-01",
    "created_at": "2026-05-01T09:12:34Z"
  }
}

Verifying signatures

Each delivery includes three headers: X-Bluecrest-Signature (hex-encoded HMAC-SHA256 of the raw body, signed with your webhook secret), X-Bluecrest-Event (the event type string, e.g. disruption.ingested), and X-Bluecrest-Delivery (a unique delivery UUID for idempotent processing). Always verify the signature against the raw body bytes before parsing JSON — parsing first can alter whitespace and invalidate the digest.

Bluecrest retries failed deliveries up to 3 times with exponential backoff: 5s → 25s → 125s. A delivery is considered failed if your endpoint returns a non-2xx status or times out after 10s. Sandbox deliveries carry no timestamp or nonce — replay protection is not enforced in sandbox mode.

import hmac, hashlib

def verify_bluecrest_signature(
    payload_bytes: bytes,
    signature_header: str,
    secret: str
) -> bool:
    expected = hmac.new(
        secret.encode(), payload_bytes, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature_header)

# FastAPI example:
# sig = request.headers.get("X-Bluecrest-Signature")
# body = await request.body()
# if not verify_bluecrest_signature(body, sig, WEBHOOK_SECRET):
#     raise HTTPException(status_code=401)

Sandbox

POST/v1/dev/sandbox/seed/{scenario_id}
Your sandbox key (wp_sandbox_…) runs against an isolated environment — no real passengers, bookings, or payments. Seed a scenario first, then exercise your integration pattern:

Airline Direct — call POST /v1/partner/airline/disruptions with any PNR and passenger_id values you choose. The response echoes them back — use those same IDs in subsequent compensation and rerouting calls.

Sandbox mock data: Rerouting options always return three sandbox flights (AA100, VS4, UA901 — tomorrow UTC) regardless of the route you submit. Compensation eligibility is computed against your actual submitted route and disruption type. Your submitted passenger IDs and PNRs are persisted and echoed back correctly. Production returns live Bluecrest inventory matched to the submitted route.

Kiosk — use the test credentials from the scenario table below.

Webhook deliveries fire against your registered URL in real time. If you are testing locally, expose your endpoint with a tunnel such as ngrok (ngrok http 3000) before registering a webhook URL — sandbox cannot reach localhost directly.

Parameters

ParameterTypeRequiredDescription
scenario_idstring (path)requiredscenario_delay_2h | scenario_cancelled | scenario_claim_eligible
# Seed a test scenario
curl -X POST https://api.bluecrestlab.com/v1/dev/sandbox/seed/scenario_cancelled \
  -H "X-API-Key: YOUR_API_KEY"

# Check sandbox state
curl https://api.bluecrestlab.com/v1/dev/sandbox/state \
  -H "X-API-Key: YOUR_API_KEY"

# Reset all sandbox data
curl -X POST https://api.bluecrestlab.com/v1/dev/sandbox/reset \
  -H "X-API-Key: YOUR_API_KEY"
Response200 OK
{
  "active_scenarios": ["scenario_cancelled"],
  "disruption_events": 1,
  "passengers": 5,
  "cases": 0,
  "last_reset": "2026-05-01T08:00:00Z"
}

2-hour delay — BA123

scenario_delay_2h

PNR: SBTEST1 / SBTEST2 / SBTEST3 · Last name: SMITH / JONES / PATEL

Tests compensation eligibility (≥2hr delay on EC261 route)

Cancellation — BA456

scenario_cancelled

PNR: SBCANC1–5 · Last name: ANDERSON / BROWN / CLARK / DAVIS / EVANS

Tests disruption ingestion and full passenger claim journey

Claim eligible — EK202

scenario_claim_eligible

PNR: SBCLAIM1 · Last name: ANDERSON

Passenger pre-confirmed disrupted — triggers webhooks immediately on ingestion

Errors

All errors return JSON with a detail field describing the problem. Use the HTTP status code to determine the error class.

CodeNameDescription
400Bad requestValidation error — detail is a string describing the problem
401UnauthorisedMissing or invalid X-API-Key header
404Not foundResource doesn't exist or belongs to another account
409ConflictIdempotency key already used with different parameters
422UnprocessableSchema validation failed — detail is an array of {loc, msg, type} objects identifying each invalid field
429Rate limitedToo many requests — back off and retry
500Server errorInternal error — contact support if it persists