Skip to main content
Webhooks push booking lifecycle events to your server so you don’t have to poll. Register an HTTPS endpoint and Jinko sends a signed POST the moment a booking is confirmed or fails. The one-line version:

Prerequisites

  • A Jinko account and a user-bound API key (jnk_...). Get one.
  • An HTTPS endpoint that can receive a POST (must be https:// and publicly reachable).
/v1/webhooks does not accept tenant keys. A tenant-scoped key (jnk_t_…) is rejected on every route under /v1/webhooks. This is deliberate, not a gap: subscription management is an account-owner action, so it is bound to a person, not to a machine credential.If you hold a tenant key, register your endpoint in the dashboard instead, at Dashboard → Webhooks, picking your tenant from the selector. Bookings made with that tenant key then deliver to that subscription. There is no plan to add a webhooks scope to tenant keys, so don’t build around one arriving.

Tenant-key bookings deliver to the tenant’s own subscription

A booking made with a tenant key is owned by the tenant, not by a person, and its events go to the subscriptions registered against that tenant in the dashboard. Nothing about the payload, the headers, or the signature differs from a user-key delivery: the only difference is which subscription list the platform resolves. Register the endpoint once, in the dashboard, with your tenant picked in the selector. Then book with the tenant key. Every subscription that tenant owns and that names the event receives the same signed POST a user-key booking would produce.
Availability, as of 7 September 2026. Tenant-key delivery arrives with published contract 0.5.0. On sandbox it works once that release is deployed there; check info.version on the OpenAPI document for the environment you are calling. On production it additionally waits on a separate platform release, so a production booking made with a tenant key does not reach a tenant subscription yet.Bookings made with a user-bound key are unaffected in both environments and deliver normally.Nothing on your side needs to change when it lands: register the subscription in the dashboard now and it starts receiving. This note is removed once both releases have shipped.

1) Register an endpoint

Go to Dashboard → Webhooks, click Add webhook, paste your URL, pick the events, and Create. Copy the signing secret shown once. You’ll need it to verify deliveries.

2) Events

Exactly one of the three fires per trip. They are mutually exclusive.
booking.partial is not a success. If you subscribe to it, treat it as “money moved and the trip is incomplete”, and reconcile per item using the data object below. If you do not subscribe to it, a partially-fulfilled trip sends you nothing at all, and you will only find it by polling get_trip.This is why booking.partial is a distinct event rather than a flag on booking.completed: a consumer that has never heard of it cannot silently mistake a half-booked trip for a confirmed one.
More event types will be added over time. Treat the event field as an open enum and ignore events you don’t handle. booking.partial arrived in published contract 0.2.0. Check info.version in the OpenAPI document to confirm which contract an environment is serving.

3) Payload

Deliveries are intentionally thin: identifiers only, no traveler PII. Fetch full detail with get_booking using the booking_ref.
Those six fields are on every event and never change.

booking.partial adds a data object

booking.partial carries one extra top-level field, data, describing what actually happened per item and how much was captured. booking.completed and booking.failed do not carry data, so nothing changes for consumers you already have in production.
Amounts here are in major units (188.65), matching the Money shape used across the trip and checkout responses. This differs from the minor-unit form used elsewhere in the platform, so don’t divide by 100.
The event_id for a partial is evt_<fulfillment_cart_id>_booking.partial, one per trip. Retries reuse it, so your existing dedupe on X-Jinko-Event-Id covers it with no change.
Each request also carries these headers:

4) Verify the signature

Compute HMAC-SHA256(secret, "<X-Jinko-Timestamp>.<raw request body>") and compare it, in constant time, to the hex in X-Jinko-Signature (after the sha256= prefix). Use the raw request body: parsing and re-serializing the JSON will change the bytes and break the check.
Reject the request if the signature doesn’t match, or if X-Jinko-Timestamp is older than your tolerance (e.g. 5 minutes) to guard against replays. Respond 2xx once you’ve accepted the event.

5) Retries & idempotency

  • A non-2xx response (or a timeout) is retried with exponential backoff, up to 8 attempts over several hours.
  • Retries mean you may receive the same event more than once. Deduplicate on X-Jinko-Event-Id (a given business event always carries the same id).
  • Return 2xx as soon as you’ve durably recorded the event; do slow work asynchronously so you don’t trip the delivery timeout.

6) Test it

Use Send test in the dashboard, or:
This delivers a sample event with "livemode": false and booking_ref: "JNK-TEST00", so you can confirm your signature handling end-to-end without a real booking.