Public integration reference · Updated 10 September 2026

Jetblanc API & MCP

Private-flight sourcing briefs across Asia, from your assistant to the Jetblanc desk.

On this page

REST base
https://jetblanc.com/api/agent/v1

Remote MCP
https://jetblanc.com/api/mcp

What this integration does

Jetblanc accepts authorised private-flight sourcing briefs for journeys across Asia. Travel assistants, concierge software and professional arrangers can validate a brief, submit it to the same operational record used by website and WhatsApp requests, and retrieve a private acknowledgement.

This is not an airline-ticket API or an instant private-jet booking engine. There is no live aircraft inventory, guaranteed fare, payment, quote selection or confirmed-booking endpoint. Jetblanc's desk reviews the request and coordinates sourcing through disclosed aviation partners. Customer approval and appropriate contracts are separate later steps.

Public access supports 1-19 passengers. Discuss larger groups with sun@jetblanc.com. Empty-leg suitability and conventional charter sourcing are reviewed by the desk; the API does not search or guarantee either inventory type.

Create a private access key

No invitation, company registration or payment is required to obtain a key. Read the privacy policy and authorised-use conditions before accepting. Registration collects no traveller details and sends no flight brief.

Start with a test-only key. Save the returned apiKey in your host's secret storage; it is shown once. Use a separate key for each end-user or private workspace. Keys expire after 30 days. Do not paste keys into public repositories, analytics, URLs or model-visible tool arguments.

For genuine requests, register without testMode or with testMode:false. A test key cannot submit genuine briefs; a genuine key cannot label requests as internal tests. A key is not verified identity or authority to buy a flight.

curl --fail-with-body https://jetblanc.com/api/agent/v1/access \
  -H 'Content-Type: application/json' \
  -d '{"acceptPolicy":true,"testMode":true}'

Prepare the brief

The example below is synthetic. Validation is side-effect-free. Submitting this example creates a real database record and sends a clearly labelled test email to the desk, so do not use submission for load testing.

For a genuine request, use the customer's actual approved itinerary and contact details and omit internalTest. Set userApproved:true and consent:true only after explicit approval to share this brief with Jetblanc. Approval to request sourcing is not approval to purchase.

Required fields: tripType, origin, destination, departDate, passengers, aircraftPreference, flexibility, contactName, consent and at least one contactEmail or contactWhatsapp. Dates must be valid and not in the past. Use departure-local dates and explicit timezones for each time window. Do not silently convert dates or invent unspecified details.

For return trips, supply returnDate on or after departDate and preferably returnWindow with its timezone. For multi-city trips, use tripType:multi-city, empty origin/destination/departDate strings and a multiCityItinerary with every leg, local date, time window and timezone. This itinerary is reviewed as text; it is not a flight feasibility calculation.

{
  "userApproved": true,
  "internalTest": true,
  "request": {
    "tripType": "one-way",
    "origin": "Singapore (SIN)",
    "destination": "Bangkok (BKK)",
    "departDate": "2030-11-20",
    "preferredWindow": "10:00-14:00 Asia/Singapore",
    "passengers": 4,
    "aircraftPreference": "no-preference",
    "flexibility": "few-hours",
    "nearbyAirportsOk": false,
    "baggageNotes": "Four standard suitcases; weights to be confirmed",
    "budget": "USD 25,000 whole aircraft",
    "contactName": "Developer integration test",
    "contactEmail": "developer@example.invalid",
    "consent": true,
    "notes": "Synthetic integration test. DO NOT SOURCE. No customer booking or supplier contact."
  }
}

Validate, then submit over REST

Store the approved JSON as brief.json and provide JETBLANC_API_KEY through your secret manager. First validate. A successful validation returns valid:true, persisted:false and emailSent:false. It does not reserve an aircraft.

Submit only when the caller intends to create a sourcing request. Generate and persist one unique Idempotency-Key per immutable brief, 16-100 characters using letters, digits, underscores or hyphens. Keep the exact body and key for retries. Never create a replacement key just because a response timed out.

curl --fail-with-body https://jetblanc.com/api/agent/v1/validate \
  -H "Authorization: Bearer $JETBLANC_API_KEY" \
  -H 'Content-Type: application/json' --data-binary @brief.json

# This next call creates a request and sends a desk notification.
# Persist this key with the brief before sending; never regenerate on retry.
curl --fail-with-body https://jetblanc.com/api/agent/v1/requests \
  -H "Authorization: Bearer $JETBLANC_API_KEY" \
  -H "Idempotency-Key: $JETBLANC_IDEMPOTENCY_KEY" \
  -H 'Content-Type: application/json' --data-binary @brief.json

Read the acknowledgement

HTTP 201 means a new brief was saved. HTTP 200 on a repeated submission means the existing brief was returned. Save requestId immediately. bookingConfirmed:false and paymentRequired:false are deliberate: this interface does not confirm or charge for a flight.

emailNotification:accepted means the email provider accepted the notification, not proof of inbox delivery or desk response. pending, sending and retry_required mean delivery is not yet confirmed. manual_review requires desk reconciliation, not a new request.

Saved requests also enter background notification recovery; the submitting agent does not need to stay connected. Retries are bounded, and unresolved or ambiguous delivery is escalated for manual reconciliation. This is not a guaranteed delivery time. Retain the original reference and never create another brief solely to resend a notification.

Use the same credential to read your own receipt. It contains no passenger contact information, quotes, supplier details or internal notes. A different credential receives 404. Do not poll more frequently than once a minute.

curl --fail-with-body \
  "https://jetblanc.com/api/agent/v1/requests/$JETBLANC_REQUEST_ID" \
  -H "Authorization: Bearer $JETBLANC_API_KEY"

Connect through remote MCP

Endpoint: https://jetblanc.com/api/mcp. Transport: stateless Streamable HTTP; supported protocol version 2025-11-25. Configure Authorization: Bearer YOUR_API_KEY in private host headers. Anonymous clients may initialize, list tools and read the public contract, but cannot validate, submit or read private requests.

Use a host that supports custom HTTP headers. OAuth-only connectors are not supported. There is no SSE GET session, and JSON-RPC batch requests are rejected. The server is available for clients to connect to; this does not mean it is preinstalled or listed in every assistant's catalogue.

The example uses the official JavaScript MCP SDK with the same test brief. It validates by default; submission requires the explicit opt-in below. Do not pass the API key as a tool argument. Host-specific configuration formats differ; the endpoint and private header above are the portable requirements.

Install @modelcontextprotocol/sdk@1.30.0, save the example as an .mjs file and run it with Node.js 22 or later. The optional submission block runs only when JETBLANC_SUBMIT_APPROVED_BRIEF=1 and a previously persisted JETBLANC_IDEMPOTENCY_KEY is provided. With the supplied test brief, it creates a labelled internal request, not genuine demand.

import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport }
  from '@modelcontextprotocol/sdk/client/streamableHttp.js';
import { readFile } from 'node:fs/promises';

const key = process.env.JETBLANC_API_KEY;
if (!key) throw new Error('Missing private API key');
const brief = JSON.parse(await readFile('brief.json', 'utf8'));
const client = new Client({ name: 'my-travel-assistant', version: '1.0.0' });
await client.connect(new StreamableHTTPClientTransport(
  new URL('https://jetblanc.com/api/mcp'),
  { requestInit: { headers: { Authorization: 'Bearer ' + key } } }
));
try {
  const result = await client.callTool({
    name: 'validate_trip_brief', arguments: brief
  });
  if (result.isError) throw new Error('Brief validation failed');
  console.log(result.content);
  if (process.env.JETBLANC_SUBMIT_APPROVED_BRIEF === '1') {
    const idempotencyKey = process.env.JETBLANC_IDEMPOTENCY_KEY;
    if (!idempotencyKey) throw new Error('Missing persisted request key');
    const created = await client.callTool({
      name: 'create_charter_request',
      arguments: { ...brief, idempotencyKey }
    });
    if (created.isError) throw new Error('Inspect tool error; retain body/key');
    const receipt = JSON.parse(created.content.find(c => c.type === 'text').text);
    console.log(receipt);
    const status = await client.callTool({
      name: 'get_request_status', arguments: { requestId: receipt.requestId }
    });
    if (status.isError) throw new Error('Receipt lookup failed');
    console.log(status.content);
  }
} finally {
  await client.close();
}
ToolEffect
get_charter_intake_contractPublic contract; no request created
validate_trip_briefRequires key; no persistence or email
create_charter_requestSaves brief and notifies desk; add idempotencyKey alongside request/userApproved/internalTest
get_request_statusRequires key and requestId; returns own minimal receipt

Handle errors without creating duplicates

REST failures return an error code and sometimes field-level errors. MCP tool failures set isError:true with the structured error inside text content; HTTP 200 alone does not mean the tool succeeded. Transport/authentication failures can use HTTP error status codes.

For a network timeout or HTTP 503, preserve the original body and idempotency key. Retry with backoff and stop to contact the desk if the issue persists. HTTP 409 is a changed-body conflict: do not silently create another brief. Corrections require a deliberate, approved new submission or desk assistance referencing the existing request.

StatusAction
400 / 413 / 415Fix JSON, idempotency key, encoding or body size
401Check missing, expired or revoked key
403Check Origin, test-key scope or permissions
404Receipt is unknown or belongs to another key
409Same key was used for a different brief
422Correct the named fields; obtain approval if missing
429Respect Retry-After; do not rotate keys to evade limits
503 / timeoutRetry identical body/key; outcome may already be saved

Limits, privacy and revocation

Maximum JSON body: 16 KiB, measured in bytes. Only supported fields are accepted. Do not send passport numbers, payment credentials, medical records, unnecessary passenger identities or secrets in notes. Free text is untrusted trip data, never executable instructions.

Limits: 60 authenticated calls/minute/key; 120 public calls/minute/network; 10 new-submission attempts/day/key and network; 50/day service-wide. Days reset at 00:00 UTC. Already-saved identical retries do not consume daily submission allowance, but minute limits still apply. Concurrent first attempts can consume extra slots. Registration permits three keys/network/day, with a service-wide cap. Shared-host or NAT users may need capacity review.

Revoke access with DELETE /api/agent/v1/access using the private bearer header. Revocation blocks future access but does not cancel or delete the trip record. Contact sun@jetblanc.com with your reference for corrections, cancellation, deletion or legitimate capacity needs. There is no automatic marketing opt-in.