Charters

Client integrations API

Book cars from your own systems — your BPM, Zoho Creator, FastCollab, an ERP — and get trip updates pushed to your URLs. Your vendor creates the integration; your admin manages keys, field mappings and subscriptions in Integrations. Machine-readable spec: OpenAPI 3.1.

Keys and limits

Send your integration key in x-api-key (or Authorization: Bearer). A key only reaches your organisation and only the bookings created through its integration. cik_live_… keys book for real; cik_test_… keys are the sandbox. Each key is rate limited (default 120 requests a minute; a 429 carries Retry-After).

curl -H "x-api-key: cik_live_…" https://<your-host>/api/integrations/v1/catalog

The catalog lists duty types and vehicle classes in your words (your vendor maps your terms, e.g. "AIRPORT DROP" → their airport transfer), your cost centres, entities and the statuses you will see.

Create a booking

POST /api/integrations/v1/bookings
{
  "client_ref": "TKT-10042",                 // your ticket no. — sending it again never books twice
  "passenger": { "employee_code": "T1003" },  // or { "name", "phone", "email" }
  "duty_type": "AIRPORT DROP",               // your term (see /catalog)
  "vehicle_class": "Sedan",
  "pickup_at": "2026-10-10T06:30:00+05:30",  // ISO, unix seconds or "10-Oct-2026 06:30:00" (IST)
  "pickup": { "address": "Koramangala, Bengaluru", "lat": 12.935, "lng": 77.624 },
  "drop":   { "address": "Kempegowda International Airport T1" },
  "flight": { "number": "6E2341" },
  "cost_centre": "CC-104", "purpose": "Client visit",
  "approval": { "status": "approved", "approved_by": "R. Iyer", "reference": "APR-881" }
}
→ 201 { "id": "bk_…", "number": "BK-2610-0042", "client_ref": "TKT-10042", "status": "confirmed",
        "duties": [{ "number": "BK-2610-0042-1", "status": "confirmed", "driver": null, "vehicle": null }] }
→ 200 { …same booking…, "duplicate": true }   (the same client_ref again)

Your travel policy, booking restrictions and the vendor's cut-off apply as for any booking. approval is honoured only when your vendor set the integration to trust your approvals; otherwise the booking waits in awaiting_approval.

Errors

422 { "error": { "code": "VALIDATION_FAILED", "message": "Some fields are missing or invalid",
                 "fields": [ { "field": "duty_type", "issue": "unknown duty type \"Helicopter\"; use one of: AIRPORT DROP, Full Day, …" },
                             { "field": "passenger", "issue": "no active employee with code T9999" } ] },
      "request_id": "req_…" }
HTTPcodemeaning
401INVALID_KEY / UNAUTHENTICATEDmissing, wrong or revoked key
403INTEGRATION_PAUSEDyour vendor paused the integration
404NOT_FOUNDnot a booking of this integration
409NOT_EDITABLE / NOT_CANCELLABLE / IN_PROGRESSthe car is already out, or the same client_ref is being processed
422VALIDATION_FAILED / POLICY_BLOCKED / CUTOFF / RESTRICTEDfix the request
429RATE_LIMITEDslow down (Retry-After)

Read, change, cancel

GET   /api/integrations/v1/bookings/TKT-10042          (your client_ref or our id)
PATCH /api/integrations/v1/bookings/TKT-10042          { "pickup_at": "…", "drop": { "address": "…" }, "vehicle_class": "SUV" }
POST  /api/integrations/v1/bookings/TKT-10042/cancel   { "reason": "Meeting moved" }

Changes are accepted until the car leaves for the pickup; cancelling twice answers duplicate: true.

Sandbox

With a cik_test_ key every call is validated against the real catalogue, employees and cost centres, but nothing is booked. Move a test booking through the trip and receive the events at your sandbox subscriptions:

POST /api/integrations/v1/sandbox/bookings/TKT-1/simulate { "event": "duty.driver_assigned" }
events: booking.confirmed, booking.rejected, duty.driver_assigned, duty.driver_changed, duty.dispatched, duty.arrived, duty.started, duty.completed, duty.no_show, duty.cancelled, duty.delayed, invoice.issued

Status updates (subscriptions)

Your admin adds your https URLs and picks the events. Each update is POSTed as JSON, signed, and retried with back-off for about a day if your endpoint does not answer 2xx; your own API header (for example x-api-key) can be stored with the subscription and is sent on every call.

eventwhen
booking.createdBooking received
booking.confirmedBooking confirmed
booking.approvedApproved
booking.rejectedRejected / denied
booking.cancelledBooking cancelled
duty.driver_assignedDriver & vehicle assigned
duty.driver_changedDriver / vehicle changed
duty.dispatchedDriver on the way
duty.arrivedDriver arrived
duty.startedTrip started
duty.completedTrip completed
duty.no_showPassenger no-show
duty.cancelledTrip cancelled
duty.delayedRunning late
booking.flight_updateFlight change
invoice.issuedInvoice issued
statuslabelFastCollab trip_status
awaiting_approvalAwaiting approvalrequesting
rejectedNot approveddenied_by_vendor
confirmedConfirmed — vehicle allotment pendingscheduled
assignedVehicle & driver assigneddriver_assigned
changedVehicle/driver changeddriver_reassigned
on_the_wayOn the waydriver_dispatched
arrivedArriveddriver_arrived
on_tripOn tripactive
completedCompletedcompleted
cancelledCancelledcancelled
no_showNo-showno_show
POST <your URL>
X-Charters-Event: duty.driver_assigned
X-Charters-Event-Id: evt_…            (deduplicate on this)
X-Charters-Signature: t=1791349200,v1=<hex HMAC-SHA256(secret, "1791349200." + raw body)>
{ "id": "evt_…", "event": "duty.driver_assigned", "created_at": "…",
  "data": { "client_ref": "TKT-10042", "status": "assigned", "status_label": "Vehicle & driver assigned",
            "booking": { "id": "bk_…", "number": "BK-2610-0042", … },
            "duty": { "number": "BK-2610-0042-1", "driver_name": "Ramesh P", "vehicle_number": "KA01AB1234", "vehicle_model": "Toyota Etios" } } }

Payload templates: Charters (above), FastCollab (trip_id, reference_id, trip_status, trip_pickup_time, driver, vehicle), Zoho Creator ({ data: { Ticket_No, Booking_Status, Driver_Name, Vehicle_Number, Pickup_Date_Time, … } }) or a custom JSON template with placeholders such as {{client_ref}}, {{status_label}}, {{duty.vehicle_number}}. Passenger names, phones and emails are never sent; the driver's name and car appear once they are assigned to your trip.

Zoho Creator and your own BPM

Point your workflow's webhook at /api/integrations/inbound/<integration id> with the key header. Zoho integrations start with a preset for Creator field names (Ticket_No, Employee_ID, Trip_Type, Vehicle_Type, Pickup_Date_Time, Pickup_Location, Drop_Location, Cost_Center, Approval_Status, Action); any other payload is mapped field by field with JSON paths, value maps and date formats — try it in the test console before going live. Action = New / Modify / Cancel selects create, update or cancel. Optional signing (recommended):

X-Charters-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256(signing secret, "<t>.<raw body>")>   // refused when older than 5 minutes

// Zoho Deluge
t = zoho.currenttime.toLong() / 1000;
sig = zoho.encryption.hmacsha256(secret, t + "." + body.toString(), "base64");   // hex or base64 both accepted
invokeurl [ url: url  type: POST  parameters: body.toString()
            headers: {"x-api-key": key, "X-Charters-Signature": "t=" + t + ",v1=" + sig, "content-type": "application/json"} ];

FastCollab (keep your existing calls)

The FastCollab endpoints, payloads, the x-api-key header and the { status, response: { data }, success } envelope are unchanged. Change the base URL from https://fleet-api.tylt.co.in/partners/fastcollab to https://<your-host>/partners/fastcollab and use the new key. Organisation, duty-type, vehicle-type and customer ids from your earlier system keep working after the migration.

beforeherenote
GET /parent-organisations, /helpdesks, /duty-types, /vehicle-types, /citiessameonly your organisation and its entities
POST /bookingssame payloadreference_id is now an idempotency key — a retry returns the same trip_id with duplicate: true
PUT /bookings/:trip_idsame whitelisttrip_notes are appended (the reference is kept)
POST /bookings/:trip_id/cancelsameonly trips created through your key
—GET /bookings/:trip_idnew: poll a trip's status, driver and vehicle
no callbackssubscriptions (FastCollab template)status updates pushed to your URL