Lakpura® API Transfers v1 — start here Full reference  ·  openapi.yaml served by ganymede.lakpura.com

Integrating with the Lakpura Transfers API

You send us point-to-point transfer bookings in Sri Lanka; we quote them and fulfil them with our fleet. This page is everything you need in the order you need it. The full reference has every field.

1. Three things that surprise people

Sandbox and production are the same URL. There is no /sandbox/ path and no separate hostname — your key selects the environment. A test key can only ever reach sandbox. Going live is a credential swap, not a code change. Every response tells you which environment answered, via the X-Lakpura-Env header and an env field.
“No availability” is a 200, not an error. When we can’t serve a journey you get 200 with an empty offers array and a declined object. Please don’t log it as a failure, count it toward an error budget, or trip a circuit breaker on it — it’s a normal answer, and the reason is usually actionable (a later pickup time, or coordinates instead of a place name).
You are billed the price you were quoted. Offers lock for 30 minutes and a booking carries an offer_id. We never re-price at booking time. After 30 minutes the offer is 410 offer_expired — ask for a fresh quote rather than retrying the booking.

2. Your keys

We issue your keys and send them to you. They look like this — the test / live word is just so you can read one at a glance:

lakpura_sk_test_a3f19c04b7e2d581_9f3c…   ← sandbox
lakpura_sk_live_60650be97f12ca25_27c1…   ← production

Send it on every request:

Authorization: Bearer lakpura_sk_test_a3f19c04b7e2d581_9f3c…

X-Api-Key: <token> also works if a bearer header is awkward in your stack.

We store only a hash, so we cannot read your key back to you — if you lose it, we issue a new one. Rotating causes no downtime: ask us for a replacement, deploy it, then tell us to revoke the old one. Both work in the meantime.

Every authentication failure returns the same 401 body, whatever the cause. That is deliberate; if you are stuck, check /ping and talk to us rather than guessing.

3. Try it in four calls

Fastest route: try it in the browser. The reference page is also a live console. Click Authorize, paste your sandbox key, then Try it outExecute on any endpoint — no curl, no Postman collection to import. Calls are real sandbox calls. The console only accepts lakpura_sk_test_… keys: an accidental Execute on POST /bookings with a production key would dispatch an actual vehicle.

The same four calls with curl, if you prefer:

Check the key

curl https://api.lakpura.com/transfers/v1/ping \
  -H "Authorization: Bearer $LK_KEY"

{"ok":true,"env":"sandbox","partner":"Your Company","time":"2026-07-17T10:33:15+00:00"}

Quote a journey

Place names can be free text — "Galle", or a full hotel address. Coordinates help when a name is ambiguous. Airports work by name or iata, and an airport at either end is what makes a journey an arrival or a departure.

curl -X POST https://api.lakpura.com/transfers/v1/quotes \
  -H "Authorization: Bearer $LK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "pickup":  { "name": "Colombo (CMB) Airport", "iata": "CMB" },
        "dropoff": { "name": "Galle" },
        "pickup_datetime": "2026-08-02T14:30:00+05:30",
        "passengers": { "adults": 2, "luggage": 2 }
      }'
{
  "env": "sandbox",
  "quote_id": "561055ebbfef36165bd76359adcc634f",
  "expires_at": "2026-07-17T11:03:47Z",
  "currency": "USD",
  "offers": [
    { "offer_id": "a7c4e1f09b3d5628e4f1a0c73d8b2e95",
      "vehicle_code": "STANDARD_CAR",
      "vehicle": "Standard Car or similar",
      "price": 84.71, "currency": "USD",
      "max_passengers": 3, "max_luggage": 3 }
  ]
}

Book an offer

curl -X POST https://api.lakpura.com/transfers/v1/bookings \
  -H "Authorization: Bearer $LK_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7" \
  -d '{
        "offer_id": "a7c4e1f09b3d5628e4f1a0c73d8b2e95",
        "quote_id": "561055ebbfef36165bd76359adcc634f",
        "partner_reference": "ACME-2026-99812",
        "passenger": { "first_name": "Ada", "last_name": "Lovelace",
                       "email": "[email protected]", "phone": "+447700900123" },
        "passengers": { "adults": 2 },
        "flight_number": "UL504"
      }'
HTTP/1.1 201 Created
{
  "env": "sandbox",
  "booking_ref": "LK7ANBH4QA",
  "partner_reference": "ACME-2026-99812",
  "status": "confirmed",
  "price": 84.71, "currency": "USD",
  "meeting_instructions": "Meet & greet at the arrivals hall — our representative will hold a Lakpura name board.",
  "emergency_phone": "+94112354550"
}

booking_ref is ours — use it to read or cancel. Keep your own partner_reference too.

Read it back, and cancel

curl https://api.lakpura.com/transfers/v1/bookings/LK7ANBH4QA \
  -H "Authorization: Bearer $LK_KEY"

curl -X POST https://api.lakpura.com/transfers/v1/bookings/LK7ANBH4QA/cancel \
  -H "Authorization: Bearer $LK_KEY"

Cancelling twice is not an error. Retrying is safe.

4. Declines: what each reason means

All of these arrive as 200 with "offers": [].

reasonWhat it meansWhat to do
short_noticePickup is inside our 24-hour minimum lead time.Quote a later pickup. Expected, not a fault.
no_vehicleNothing in our fleet fits that party on that route.Try fewer passengers/bags, or omit vehicle_codes.
route_unknownWe could not price that journey.Send lat/lon — free-text-only names are the usual cause.
below_min_rateThe journey prices below our minimum fare.Nothing on your side. Very short hops.
partner_pausedQuoting is paused on your account.Talk to us — it is deliberate on our end.

5. Retrying safely

You cannot accidentally book two cars. Three separate things prevent it:

MechanismBehaviour
Idempotency-Key headerSame key + same body → the original response, as 200 (not 201 — so you can tell a replay from a fresh booking). Same key + different body → 409 idempotency_conflict, which means a bug your side.
partner_referenceUnique per account. Re-posting the same one returns the existing booking as 200.
offer_idAn offer is consumed, not re-executed. Booking one twice returns 409, never a second car.

503 is the only status worth retrying blindly (with backoff). 4xx means something needs changing first.

6. Errors

Every error has the same shape. Branch on error.code, never on the message — the prose may change, the code will not.

{ "error": { "code": "offer_expired",
             "message": "That offer has expired. Request a new quote.",
             "details": { "offer_id": "a7c4e1f0…", "expired_at": "2026-07-17T11:03:47Z" } } }
StatuscodeMeaning
400invalid_requestWe could not understand the body.
401unauthorizedMissing, malformed, unknown or revoked key.
404not_foundNo such booking or offer on your account.
409idempotency_conflict / booking_conflictSee “Retrying safely”.
410offer_expiredOffer older than 30 minutes. Re-quote.
429rate_limitedReserved. We do not rate-limit today; handle it so we can add it without breaking you.
503service_unavailableTemporary. Retry with backoff.

7. Vehicles

Offers come back in your vehicle vocabulary. Send us your codes (e.g. SEDAN, MPV5) and we map them to our fleet — until then you will see ours. Codes we do not recognise are ignored, never rejected, so adding a vehicle type on your side can never break your quotes.

Our fleet, with what each seats:

VehicleClassPassengersLuggage
Small CarEconomy32
Standard CarStandard33
Premium CarBusiness33
SUVStandard44
Standard VanStandard77
Premium VanBusiness77
Large VanStandard99
Standard BusStandard2020

8. Going live

  1. /ping returns 200 with "env":"sandbox".
  2. You can quote, book, read and cancel end to end in sandbox.
  3. A decline is handled as a normal empty result, not an error.
  4. You send an Idempotency-Key on every booking.
  5. An expired offer is handled by re-quoting, not retrying.
  6. Your vehicle mapping is agreed with us.
  7. We issue the production key. You swap the credential — nothing else changes.
  8. Confirm /ping now reports "env":"production", then send one real booking and check it with us before opening the taps.

Help

Talk to your Lakpura contact. It speeds things up enormously if you include the quote_id or booking_ref and roughly when the call happened — we log every request and can look up exactly what we received and answered.