Skip to content
Public API · v1

Order Push API

Push transfer bookings into Monaco Airport Transfer straight from your own site or platform. One HTTP request creates one order.

Overview

A REST endpoint that lets an external site push a transfer booking into Monaco Airport Transfer. The order lands in the operator's desk exactly like a hand-typed one, and can optionally auto-list on the driver exchange.

The flow is inbound only: your platform calls us. We never call back — so there's nothing to configure on your end beyond the token.

Endpoint

POST https://monaco-airport-transfer.shop/api/v1/sources/orders
Content-Type: application/json
Accept: application/json

The URL is constant — sources are told apart by their token, not the URL.

Authentication

Each source gets its own secret token, generated by the operator in the admin panel (Settings → Dictionaries → Order Sources → Generate token). It's shown once — only its hash is stored — so keep it safe. Send it on every request as either header:

Authorization: Bearer <token>
# or
X-API-Key: <token>

⚠ The token is a server secret. Never ship it in browser JavaScript — anyone viewing the page could read it. Route your form through your own backend (see below).

Request fields

Send JSON. By default the keys are our field names — use field mapping if your form uses different names.

Required

Field Type Notes
pickup_address string (≤255) Where the transfer starts
dropoff_address string (≤255) Where it ends
transfer_date date e.g. 2026-08-15
transfer_time string H:i 24h, e.g. 14:30
first_name string (≤127)
last_name string (≤127)
phone string (≤50)
external_id string (≤255) Idempotency key — your booking reference. Key name is configurable (external_ref), defaults to external_id

Optional

Field Type Default if omitted
email valid email (≤255) The passenger's OWN address — see below. Omitted: no client account is linked
price number ≥ 0 unset
currency supported currency source's default currency
number_of_passengers integer 1–255 1
number_of_luggage integer 0–255 0
child_seats integer 0–255 0
child_seat_details string (≤255) null
meet_and_greet boolean false
pickup_latitude / pickup_longitude number −90…90 / −180…180, both or neither resolved from pickup_address
dropoff_latitude / dropoff_longitude number −90…90 / −180…180, both or neither resolved from dropoff_address
transfer_class class code: economy, standard, business standard
flight_train_number string (≤50) null
notes string (≤2000) null — a note for our dispatch desk, never shown to the client
receipt_note string (≤1000) null — printed on the client's receipt
language language tag, e.g. fr or fr-FR the site's default language — the client's language; only the language part is kept. Our e-mails to the client are written in it when the site your source is bound to speaks it
return_transfer_date date, both or neither no return trip — see Round trip below
return_transfer_time string H:i, both or neither no return trip
utm_source / utm_medium / utm_campaign string, cut to 255 null
referrer string, cut to 255 null

Fields we set ourselves and ignore from the payload: site, source and order status (always starts as new). An unknown transfer_class code is a 422 naming the valid ones.

Round trip

Send return_transfer_date and return_transfer_time together and we create two linked orders: the outbound, and the return leg with the route reversed. Each leg is priced and dispatched on its own. Half of the pair, or a return that starts before the outbound, is a 422 — never a silent one-way trip. The response names the return leg under return_order.

Confirmation e-mail to the client

When the booking carries the passenger's own email, we send them an "order received" confirmation under the brand of the site your source is bound to — with the route, date, flight number and return trip, in the client's language if that site speaks it. No letter goes to an address we know is a partner or office mailbox. If your platform confirms bookings itself, ask the operator to switch the letter off for your source.

E-mail — send the passenger's, or send nothing

email used to be required. It no longer is, and that change is deliberate: the address is what we group a customer's bookings under, and what a sign-in link to their cabinet is sent to. It has to be that passenger's own address.

A booking with no client e-mail is a normal booking — created, priced, dispatched and driven like any other. It simply has no client account attached until someone tells us the real address.

What not to do: put your own booking inbox or a shared mailbox in this field to satisfy a validator. Two bookings sent with the same stand-in address are read as one returning customer, and a cabinet link to that mailbox then opens a page holding both passengers' names, phones and routes. Omitting the field is always the safer answer.

Field mapping — when your names differ

If your form calls the pickup from and the reference booking_id, you don't rename anything. On the source's admin form, set Field mapping (JSON) as our field → your payload key:

{
  "pickup_address": "from",
  "dropoff_address": "to",
  "external_ref": "booking_id"
}
  • Omit a field to use its own name as the key.
  • Values may be dotted paths for nested payloads, e.g. "first_name": "customer.first_name".
  • external_ref is the special mapping key for the idempotency reference.

Example request

curl -X POST https://monaco-airport-transfer.shop/api/v1/sources/orders \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "external_id": "BK-100245",
    "pickup_address": "Prague Airport (PRG), Terminal 1",
    "dropoff_address": "Wenceslas Square, Prague",
    "transfer_date": "2026-08-15",
    "transfer_time": "14:30",
    "first_name": "John",
    "last_name": "Doe",
    "phone": "+420777123456",
    "email": "[email protected]",
    "price": 1200,
    "currency": "CZK",
    "number_of_passengers": 3,
    "number_of_luggage": 2
  }'

Browser form → your backend → us

Don't call this endpoint straight from the browser — it would leak the token and hit CORS. Post your form to your own server, and let the server forward it.

Front-end — no token here:

async function submitBooking(form) {
  const res = await fetch('/api/forward-booking', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(Object.fromEntries(new FormData(form))),
  });
  return res.json();
}

Your backend — token stays in the environment:

$payload = json_decode(file_get_contents('php://input'), true);

$ch = curl_init('https://monaco-airport-transfer.shop/api/v1/sources/orders');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('BOOKING_API_TOKEN'),
        'Content-Type: application/json',
        'Accept: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode($payload),
]);
$response = curl_exec($ch);
http_response_code(curl_getinfo($ch, CURLINFO_HTTP_CODE));
echo $response;

Responses

Status Meaning
201 Created Order created
200 OK Idempotent repeat — same external_id already exists; the original order is returned, nothing is duplicated
409 Conflict That external_id already belongs to a different booking. Nothing was created — send a unique reference per booking
422 Unprocessable Entity Validation failed; body has Laravel's per-field errors object
401 Unauthorized Missing / unknown / disabled token, or source not of type api. Opaque on purpose
429 Too Many Requests Rate limit hit; may include a Retry-After header
503 Service Unavailable No active site configured on our side, or the site your source is bound to is switched off

Success body (both 201 and 200):

{
  "id": 8123,
  "external_ref": "BK-100245",
  "status": "new",
  "posted_to_exchange": false,
  "return_order": null
}

posted_to_exchange is true only when the source may auto-list on the exchange and the listing succeeded. A failed listing never fails order creation. return_order is {"id", "status", "posted_to_exchange"} for a round trip and null otherwise.

Idempotency & retries

The pair (source, external_id) is unique. If a network hiccup makes you retry with the same external_id, you get the original order back with 200 — never a duplicate. Always send a stable, unique external_id per booking, and retrying is safe.

Rate limits

  • 120 requests/minute per source — steady throughput ceiling.
  • Failed auth attempts are separately capped per IP (10 per 60s) to brake token guessing; a valid, active source is never touched by that brake.

Back off on 429 and honour Retry-After when present.

Getting set up

  1. Ask the Monaco Airport Transfer operator to create an api-type source for you and generate a token.
  2. If your field names differ from ours, agree on the field mapping.
  3. Send a test POST, confirm you get a 201 and the order appears in the desk.
  4. Go live — retry safely using a stable external_id.