Developers

ClickToGoo B2B API

A transfer quote, booking and webhook API for travel agencies, OTAs and other business customers. This page summarises authentication, endpoints, idempotency and webhook signing; the machine-readable OpenAPI spec is served live.

Open the OpenAPI spec (/api/v1/openapi.json)

Base URL & spec

All endpoints live under /api/v1. The machine-readable OpenAPI 3.1 spec is served live — use it to generate clients/SDKs.

Base URL:   /api/v1
OpenAPI:    /api/v1/openapi.json

Authentication

Every request needs an API key. Send it as a Bearer token in the Authorization header, or in the X-API-Key header. Keys are issued by ClickToGoo (there is no self-service sign-up) — contact us to request access.

Each key carries one or more scopes; an insufficient scope returns 403, a missing/invalid key returns 401.

Authorization: Bearer <api-key>
— or —
X-API-Key: <api-key>
airports:read
List supported airports.
quotes:write
Create transfer quotes.
quotes:read
Read quotes.
bookings:write
Create online-payment bookings.
bookings:cash
Supplemental authority for cash-in-vehicle bookings, which are taken only for trips in Türkiye; also requires bookings:write.
bookings:read
Read bookings.
bookings:cancel
Cancel bookings.
payments:write
Create payment sessions.
webhooks:manage
Manage webhook subscriptions.

Quickstart

With an API key, create a quote, then book the vehicle-class offer you choose by sending its quoteId and offerSnapshotId. Pickup dates and times are the airport's local time (Europe/Istanbul for airports in Türkiye), at least 3 hours and at most 365 days ahead; the quote and the booking name that zone in timeZone. The full request and response schemas are in the OpenAPI spec above.

Create a transfer quote
curl -X POST https://<host>/api/v1/quotes \
  -H "Authorization: Bearer <api-key>" \
  -H "Content-Type: application/json" \
  -d '{
  "airport": { "code": "IST", "side": "from" },
  "origin": { "query": "Istanbul Airport" },
  "destination": { "query": "Taksim, Istanbul" },
  "pickup": { "date": "2027-01-15", "time": "14:30" },
  "passengers": { "count": 2 },
  "trip": "one_way"
}'

Rate limits & quotas

Each endpoint enforces a per-client, per-minute limit, and each client has daily and monthly quotas that reset at 00:00 UTC on each calendar day and month. Failed or unauthenticated requests count against a separate abuse limit; successfully authenticated requests do not consume that abuse budget. Exceeding an applicable limit returns 429 with a Retry-After header.

Quote → Booking flow

Create a quote first (POST /api/v1/quotes) — the response contains per-vehicle-class offer snapshots. Then create a booking with the chosen snapshot (POST /api/v1/bookings). You can read, cancel, or open a payment session for a booking.

GET    /api/v1/airports
POST   /api/v1/quotes
GET    /api/v1/quotes/{quoteId}
POST   /api/v1/bookings (Idempotency-Key required)
GET    /api/v1/bookings/{bookingId}
POST   /api/v1/bookings/{bookingId}/cancel
POST   /api/v1/bookings/{bookingId}/payment-session
GET    /api/v1/webhooks
POST   /api/v1/webhooks (Idempotency-Key required)
DELETE /api/v1/webhooks/{webhookId}
POST   /api/v1/webhooks/{webhookId}/rotate-secret

Idempotency

POST /api/v1/bookings and POST /api/v1/webhooks require an Idempotency-Key header of 8–200 characters with no spaces. Replaying the same key with the same body returns the original resource with status 200 and X-Idempotency-Replayed: true (the first call returns 201). Reusing the key with a different body returns 409.

Idempotency-Key: <unique-key>

Webhooks

Events: api.quote_created, api.booking_created, api.booking_cancelled, api.booking_completed, api.booking_pickup_amended. Manage subscriptions via /api/v1/webhooks. Listing is cursor-paginated: limit defaults to 20 (maximum 100); when hasMore is true, pass nextCursor as the next cursor value.

Signing follows the Standard Webhooks spec. Each delivery carries webhook-id, webhook-timestamp and webhook-signature headers. The signature base is the string webhook-id.webhook-timestamp.<raw-json-body>; the signature is v1,<base64(hmac_sha256)> verified with your subscription secret (whsec_...).

Protect against replays: reject deliveries whose webhook-timestamp deviates more than 5 minutes from your clock (retries are re-signed with a fresh timestamp), and deduplicate on webhook-id with a window covering the full retry horizon — up to 10 attempts over roughly 76 hours (about 3.2 days) of cumulative backoff, so keep processed ids for at least 4 days. Operator replays and fanout deliveries can reuse a webhook-id beyond that schedule, so treat a remembered id as already processed.

Rotate the signing secret without downtime via POST /api/v1/webhooks/{webhookId}/rotate-secret. The new secret is returned exactly once. For 24 hours after rotation (previousSecretExpiresAt) each delivery's webhook-signature header carries two space-delimited v1 signatures — one per secret — and the delivery is authentic if either verifies. Disabling a subscription revokes the grace secret immediately.

webhook-id: <id>
webhook-timestamp: <unix>
webhook-signature: v1,<base64(hmac_sha256)>

base = webhook-id + "." + webhook-timestamp + "." + rawBody
rotation grace: webhook-signature: v1,<new> v1,<previous>
spec: https://www.standardwebhooks.com

Errors

Every error returns the same JSON shape — a stable code plus a human-readable message. 400 validation errors add a fieldErrors map keyed by field path; 429 responses add a Retry-After header (in seconds).

Error body
{
  "code": "API_QUOTE_NOT_FOUND",
  "message": "Quote was not found."
}
Validation error (400)
{
  "code": "INVALID_API_QUOTE_REQUEST",
  "message": "Check origin, destination, pickup and passenger details.",
  "fieldErrors": {
    "pickup.date": ["Use YYYY-MM-DD format."]
  }
}
400
Invalid request body — see fieldErrors.
401
Missing or invalid API key.
403
The key lacks the required scope.
404
The resource does not exist.
409
Idempotency key reused with a different body, or a conflicting state.
422
The request is valid but cannot be carried out, for example the pickup is too soon or no airport is on the route.
429
Rate limit or quota exceeded — see Retry-After.
503
Booking through the API is temporarily closed or a provider is unavailable; retry later.
Request API access

We set only the cookies this site needs to work — no analytics, no advertising, no third-party trackers. Cookie Policy