# Bambi Developer Platform API > The Bambi Developer Platform API lets approved partners create, manage, and track non-emergency medical transportation (NEMT) trips in Bambi. This is the complete Bambi Developer Platform API documentation for LLMs. The interactive reference and machine-readable schema are linked below. ## Resources - [Interactive API reference](https://staging.docs.hibambi.com/): browse the docs in a browser. - [OpenAPI schema](https://staging.docs.hibambi.com/schema/?format=json): the machine-readable specification. The Bambi Developer Platform API lets approved partners create, manage, and track non-emergency medical transportation (NEMT) trips in Bambi. ## Start here What you build depends on how you use Bambi, and most integrations use a subset of the API. Every integration authenticates and finds the organizations it can act in. The full sequence, in order: 1. **Authenticate.** Exchange your client credentials for an access token and send it on every request. 2. **List organizations.** Find the organizations you are authorized to act in. 3. **List payers.** See the payers available to you in an organization. 4. **Create a trip.** Submit a trip request for a passenger. 5. **Track a trip.** Retrieve or list trips to follow them through fulfillment. 6. **Modify a trip.** Update, cancel, retract, or activate a will-call trip. 7. **Read a trip's history.** List the events already recorded on a trip. ## Customer partners and channel partners Every partner account is one of two kinds, decided when Bambi provisions your credentials. A **customer partner** builds on an organization that is already a Bambi customer, usually its own. It runs the fleet it is reading about, and the API is a second way into data it can also see in the Bambi app. A **channel partner** sends trips to organizations it does not run. Brokers and health plans integrate this way, placing trips with many transportation providers at once, and for them the API and these docs are the whole of Bambi. One thing in the API depends on which you are. The driver and vehicle endpoints list an organization's own roster and fleet, so they are open to customer partners only. A channel partner calling them gets a `403` with the error code `customer_partner_only`, and reads driver and vehicle detail from the `assignment` on the trips it can already see. Everything else follows from your grant rather than your kind. Bambi gives your account access to one or more organizations, and within each one either every payer or a named set. A channel partner is usually scoped to the payers it books under while a customer partner usually has all of them, though that comes from how your access was granted and is worth confirming with us rather than assuming. ## Rate limits Requests are rate limited per API client. Exceeding a limit returns a `429 Too Many Requests` response. - Up to **120 requests per minute** for short bursts. - Up to **5,000 requests per hour** sustained. The token endpoint has its own, much smaller limit of **30 requests per hour**, and it is counted per IP address rather than per client, because a caller has no client identity until it authenticates. Thirty is generous for an endpoint whose answer stays valid for an hour and easy to exhaust if you request a token per call, so cache the token as the [authentication](#tag/authentication) section describes. Running out takes out every endpoint rather than just this one, since the rest need a token. If your requests leave through a shared address such as a NAT gateway or a CI runner, that budget is shared with everything else behind it. Every response includes headers describing your current budget: - `X-RateLimit-Limit`: the limit you are closest to reaching. - `X-RateLimit-Remaining`: requests remaining before a 429. - `X-RateLimit-Reset`: seconds until capacity frees up. On a `429` response, the `Retry-After` header tells you how many seconds to wait. Retry with exponential backoff and a little jitter rather than retrying immediately. ## Pagination List endpoints return one page at a time. Alongside the `results` array you get a `count` of matching records and `next` and `previous` links. - The default page size is **100**. - Set the `page_size` query parameter to ask for a different size, up to a maximum of **250**. Asking for a page larger than the maximum returns the maximum instead of an error. Walk the `next` link until it comes back `null` rather than working out page numbers from `count`, because a client that assumes it received every row it asked for will quietly skip records. A `page` beyond the last one is a `404` rather than an empty page, which is the other reason to follow `next` rather than count pages yourself. The trip list is ordered by scheduled pickup time, oldest first. To read the most recent trips, pass `ordering=-scheduled_pickup_at` and take the first page. That is far cheaper than paging through to the end of your history, and combining it with the `scheduled_pickup_at__gte` and `scheduled_pickup_at__lte` filters keeps each request small. To find the trips that changed since your last poll, see the next section on keeping up with changes. ## Keeping up with changes A trip keeps changing after you create it, as a provider assigns a driver and the driver works through the ride. If your integration can accept an HTTPS callback, [webhooks](#tag/webhooks) are the better way to follow those changes. You register an endpoint once, Bambi tells you within seconds when a trip changes, including a change you made yourself, and it costs you nothing while nothing is happening. Verify the signature on every delivery, which the section below covers. Polling is the answer when a callback is not an option. The trip list takes an `updated_at` filter for exactly this, and [its reference](#tag/trips) describes the loop. ## Errors The API returns standardized error responses. An error body has a `type` and a list of `errors`, each with a machine-readable `code`, a human-readable `detail`, and the `attr` the error applies to (or `null`). ```json { "type": "validation_error", "errors": [ { "code": "required", "detail": "This field is required.", "attr": "passenger" } ] } ``` Validation failures return `400` with type `validation_error`. Authentication failures return `401`, permission failures `403`, and missing resources `404`. A query parameter the endpoint does not recognize also returns `400`, with the parameter named in `attr`. Every endpoint checks this, so a misspelled filter fails on your first call rather than quietly returning an unfiltered result set. A field in a request body works the same way. An unrecognized name returns `400` with the field in `attr`, and a field nested inside another carries its full path, so a typo inside `pickup` comes back as `pickup.driver_note`. A `400` reports every problem it found, so an unrecognized name arrives next to the field it misspelled and one round trip shows you everything wrong with the request. The token endpoint is the one exception to all of the above. It speaks OAuth2, so bad credentials come back as `400` with an OAuth2 error body rather than the shape above: ```json { "error": "invalid_client" } ``` It also ignores parameters it does not recognize, as OAuth2 expects. ## Verifying a webhook delivery Every delivery is signed with the endpoint's signing secret so your receiver can prove it came from Bambi. Verify that signature before you act on a delivery. Anyone who learns your endpoint URL can post to it, and the signature is the only thing separating a real delivery from a forged one. Three headers carry the signature: - `svix-id`: the delivery's unique message id. - `svix-timestamp`: when Bambi signed it, in seconds since the Unix epoch. - `svix-signature`: a space-separated list of signatures, each written `v1,`. The signed content is the message id, the timestamp, and the raw request body, joined with periods: ``` .. ``` Your signing secret arrives as `whsec_` followed by base64. Strip the prefix and base64 decode the rest to get the key. Sign the content above with HMAC-SHA256 under that key. Each entry in `svix-signature` is that digest base64 encoded, so decode the entries and compare them against yours with a constant-time comparison. The delivery is genuine if any entry matches. Skip entries whose version is not `v1`. More than one `v1` entry appears while a secret is rotating, because Bambi signs with the new secret and every unexpired old one, and any of them matching is enough. Reject a delivery whose `svix-timestamp` is more than five minutes away from the current time in either direction. That is what stops someone replaying a delivery they captured earlier. Sign the raw bytes of the body exactly as they arrived. Parsing the JSON and re-serializing it changes whitespace and key order, and the signature will no longer match. Most web frameworks hand you a parsed body by default, which is the usual reason a first verifier fails. Here is a worked example in Python. It is a starting point rather than a library we support, so read it before you ship it and adapt it to how your framework hands you headers and the raw body. ```python import hmac from base64 import b64decode from binascii import Error as Base64Error from hashlib import sha256 from time import time from typing import Mapping TOLERANCE_SECONDS = 5 * 60 def is_from_bambi( secret: str, headers: Mapping[str, str], body: bytes, ) -> bool: """Whether this delivery was signed by Bambi. `secret` is the endpoint's `whsec_...` value and `body` is the raw request body, before any JSON parsing. """ headers = {k.lower(): v for k, v in headers.items()} message_id = headers.get("svix-id") timestamp = headers.get("svix-timestamp") presented = headers.get("svix-signature") if not message_id or not timestamp or not presented: return False try: age = abs(time() - int(timestamp)) except ValueError: return False if age > TOLERANCE_SECONDS: return False key = b64decode(secret.removeprefix("whsec_")) signed = f"{message_id}.{timestamp}.".encode() + body expected = hmac.new(key, signed, sha256).digest() for entry in presented.split(" "): version, _, signature = entry.partition(",") if version != "v1": continue try: candidate = b64decode(signature, validate=True) except Base64Error: continue if hmac.compare_digest(candidate, expected): return True return False ``` Send a test event to your endpoint to exercise this before any trip activity depends on it. A test delivery is signed exactly like a real one. Bambi delivers webhooks through [Svix](https://www.svix.com), so the official Svix libraries verify our deliveries as they are and are a reasonable alternative to writing the code yourself. ## Compatibility The API is not versioned. There is no version segment in the URL and no version header, and we do not plan to add one. In place of that, we commit to a set of changes that are always safe to make, and to giving notice before any other kind. We may do any of the following at any time, without warning you first: - Add a new endpoint. - Add a new optional request parameter. - Add a new field to an existing response or webhook payload. - Add a new webhook event type. - Change the order of fields in a response. - Change the length or format of an opaque string, such as a pagination cursor, a delivery message id, or the human-readable `detail` text in an error. We will not do any of the following without notice: - Remove or rename a field. - Change the type of a field. - Remove a webhook event type. - Change the shape of the webhook envelope. - Change the meaning of an existing enum value. Should one of these ever become necessary, we will give at least 90 days notice before it takes effect, and we will run the old and the new behavior alongside each other for that period wherever it is technically possible. Where a change is needed to address a security vulnerability, to protect patient health information, or to meet a legal or regulatory obligation, we may make it without that notice. We will tell you as soon as we are able. **In return, your integration should ignore anything it does not recognize** rather than treating it as an error. That covers fields you have not seen before and webhook event types you do not handle. A parser that rejects an unfamiliar field turns a routine addition on our side into an incident on yours. This matters most for webhooks, because Bambi delivers every event type to every registered endpoint with no per-endpoint filter. A receiver that errors on an unfamiliar event type fails on every delivery of that type, and sustained failures eventually stop delivery to that endpoint. Anything explicitly marked **Beta** is exempt from all of the above until that marking is removed. A Beta surface may change in any of these ways without notice. ## API reference ### Authentication The API uses the OAuth2 client credentials flow. You exchange a client ID and secret for a short-lived access token, then send that token as a `Bearer` credential on every request. Bambi provisions your credentials and delivers them over a secure channel. You receive a client ID and a client secret. Store the secret safely and treat it as sensitive. If it is ever lost or exposed, contact Bambi to reissue a new pair. Credentials are specific to an environment, so a staging client cannot call production or the reverse. Build and test against staging first. The token response includes `expires_in`, the number of seconds the token stays valid. Cache the token and reuse it until it is close to expiry, then request a new one. This endpoint allows 30 requests an hour, counted per IP address, so requesting a fresh token on every call will exhaust it quickly and leave you unable to call anything else until the hour is up. See **Rate limits** in the introduction. Bad credentials return a `400` with an OAuth2 error body, `{"error": "invalid_client"}`, rather than the standardized error shape the rest of the API uses. #### POST /oauth2/token/ **Issue an access token** Exchange your client credentials for an access token. Send the request as `application/x-www-form-urlencoded` with `grant_type` set to `client_credentials`. Use the returned `access_token` as a `Bearer` credential on every other request until it expires. Bad credentials return a `400` with an OAuth2 error body, `{"error": "invalid_client"}`, rather than the standardized error shape the rest of the API uses. Request body example: ```json { "grant_type": "client_credentials", "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET" } ``` Responses: - **400** - **404** - **429** - **200** Response example: ```json { "access_token": "eyJraWQiOiJ...", "expires_in": 3600, "token_type": "Bearer" } ``` ### Organizations Every trip belongs to an organization and is attributed to a payer within that organization. Bambi grants your partner account access to one or more organizations. Within each organization you have access to either all payers or a specific set of payers, and you can read and create trips only for payers you have been granted. #### GET /organizations/ **List organizations** List the organizations your partner account is authorized to act in. Use an organization's `id` as the `organization_id` path parameter on the payer and trip endpoints. Parameters: - `page` (query, integer, optional): A page number within the paginated result set. - `page_size` (query, integer, optional): Number of results to return per page. Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "count": 123, "next": "http://api.example.org/accounts/?page=4", "previous": "http://api.example.org/accounts/?page=2", "results": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "Acme Transportation" } ] } ``` ### Payers A payer is a party within an organization that a trip is attributed to. #### GET /organizations/{organization_id}/payers/ **List payers** List the payers you can attribute trips to within an organization. Use a payer's `id` as `payer_id` when creating a trip. Parameters: - `organization_id` (path, string (uuid), required) - `page` (query, integer, optional): A page number within the paginated result set. - `page_size` (query, integer, optional): Number of results to return per page. Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "count": 123, "next": "http://api.example.org/accounts/?page=4", "previous": "http://api.example.org/accounts/?page=2", "results": [ { "id": "9c8b7a65-4321-4dcb-a987-1234567890ab", "display_name": "Facility A" } ] } ``` ### Trips Trips are the core of the API. You create a trip as a request, follow it through fulfillment by polling the retrieve endpoint, and modify it as plans change. Retrieving a trip tells you where it stands now. The event list tells you what has already happened on it. Addresses are normalized when you write them, so a pickup sent as `350 Fifth Avenue` reads back as `350 5th Ave`. It is the same place. Match your own records to a trip on `external_trip_id` or the trip's `id` rather than on the address text. #### POST /organizations/{organization_id}/trips/ **Create trip** Create a trip request for a passenger in the given organization. Provide the passenger, the `payer_id` from the payers endpoint, the scheduled pickup time, the pickup and dropoff locations, and the space and service types. For the passenger, send either `passenger_id` with the `id` of an existing passenger taken from a trips response, or `passenger` with their first name, last name, and date of birth to match or create one. Exactly one of the two is required, and sending both is rejected. A `passenger_id` leaves the existing passenger record unchanged. Optional fields cover the appointment time, pricing, clinical and equipment needs, and your own `external_trip_id`. The trip starts in the `requested` state and the response returns its Bambi `id`. An `external_trip_id` must be unique per payer within the organization. Parameters: - `organization_id` (path, string (uuid), required): ID of the organization. Request body example: ```json { "passenger": { "first_name": "John", "last_name": "Doe", "dob": "1948-05-25" }, "payer_id": "9c8b7a65-4321-4dcb-a987-1234567890ab", "scheduled_pickup_at": "2025-06-01T14:30:00Z", "pickup": { "number": "123", "street": "Main Street", "city": "Anytown", "state": "NY", "zip": "10001", "country": "United States" }, "dropoff": { "number": "500", "street": "Medical Center Drive", "city": "Anytown", "state": "NY", "zip": "10005", "country": "United States" }, "space_type": "ambulatory", "service_type": "curb-to-curb" } ``` Responses: - **400** - **403** - **404** - **429** - **201** Response example: ```json { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7" } ``` #### GET /organizations/{organization_id}/trips/ **List trips** List the trips for an organization. Results are paginated and ordered by scheduled pickup time, ascending by default. Pass `ordering=-scheduled_pickup_at` for descending order, and filter by pickup window with the `scheduled_pickup_at__gte` and `scheduled_pickup_at__lte` query parameters. To read only what changed since your last poll, send `updated_at__gte` set to the newest `updated_at` you have seen, along with `ordering=updated_at`, and walk the `next` links. Every trip carries `updated_at`, which moves whenever Bambi records a change to it, so the bound for your next poll is in the response you just read. Two trips can share a timestamp, so set the bound a minute or two behind the newest value you saw and discard trips you have already processed by `id`. `driver_location` carries the last position the driver's device reported while working this trip. It is null before the driver sets off and for a while after the trip ends, so read `recorded_at` rather than assuming a coordinate is current. This is a convenience on a trip read rather than a tracking feed, and polling fast enough to animate a map will hit the rate limit. Parameters: - `ordering` (query, string, optional): Field to order results by. Prefix with `-` for descending order (e.g. `-scheduled_pickup_at`). Defaults to ascending scheduled pickup time. Use `updated_at` when polling for changes. - `organization_id` (path, string (uuid), required): ID of the organization. - `page` (query, integer, optional): A page number within the paginated result set. - `page_size` (query, integer, optional): Number of results to return per page. - `scheduled_pickup_at__gte` (query, string (date-time), optional): Inclusive lower bound on scheduled pickup time. ISO-8601 datetime (e.g. 2026-01-01T00:00:00Z). - `scheduled_pickup_at__lte` (query, string (date-time), optional): Inclusive upper bound on scheduled pickup time. ISO-8601 datetime (e.g. 2026-01-01T00:00:00Z). - `updated_at__gte` (query, string (date-time), optional): Inclusive lower bound on when the trip last changed. ISO-8601 datetime (e.g. 2026-01-01T00:00:00Z). Combine with ordering=updated_at to read only what changed since your last poll. - `updated_at__lte` (query, string (date-time), optional): Inclusive upper bound on when the trip last changed. ISO-8601 datetime (e.g. 2026-01-01T00:00:00Z). Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "count": 123, "next": "http://api.example.org/accounts/?page=4", "previous": "http://api.example.org/accounts/?page=2", "results": [ { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "assignment": { "vehicle": { "license_plate": "ABC123", "vin": "1XKEXAMPLE0000000", "make": "Toyota", "model": "Sienna", "year": 2022, "color": "Silver" }, "driver": { "id": "7d6e5f40-0000-4000-8000-000000000000", "first_name": "Jane", "last_name": "Doe" }, "attendants": null }, "driver_location": { "latitude": 40.712776, "longitude": -74.005974, "heading_degrees": 92.4, "speed_meters_per_second": 13.9, "accuracy_meters": 8.0, "recorded_at": "2025-06-01T14:30:00Z" }, "status": "assigned", "passenger": { "id": "d1f7c3e2-0b5a-4e6d-9c8b-1a2b3c4d5e6f", "first_name": "John", "last_name": "Doe", "dob": "1948-05-25", "email": "john.doe@example.com", "phone_number": "+12125550143" }, "payer": { "id": "9c8b7a65-4321-4dcb-a987-1234567890ab", "display_name": "Facility A" }, "external_trip_id": "ARHF-7890", "price_cents": 4500, "scheduled_pickup_at": "2025-06-01T14:30:00Z", "appointment_at": "2025-06-01T15:00:00Z", "pickup": { "full_address": "123 Main Street, Anytown, NY 10001", "number": "123", "street": "Main Street", "detail": "Apt 5B", "city": "Anytown", "state": "NY", "zip": "10001", "country": "United States", "latitude": 40.123456, "longitude": -74.123456, "num_stairs": 0, "contact_name": "John Doe", "contact_phone_number": "+12125550143", "driver_notes": "Ring the doorbell" }, "dropoff": { "full_address": "500 Medical Center Drive, Anytown, NY 10005", "number": "500", "street": "Medical Center Drive", "detail": "", "city": "Anytown", "state": "NY", "zip": "10005", "country": "United States", "latitude": 40.234567, "longitude": -74.234567, "num_stairs": 0, "contact_name": "Front Desk", "contact_phone_number": "+12125550170", "driver_notes": "Main entrance" }, "dispatcher_notes": "Passenger uses a folding wheelchair.", "estimated_distance_miles": 8.2, "is_will_call": false, "space_type": "wheelchair", "service_type": "curb-to-curb", "must_provide_wheelchair": true, "is_oxygen_required": false, "oxygen_liters_per_min": null, "num_attendants_needed": 0, "num_accompanying_passengers": 0, "has_infectious_disease": false, "seat_equipment": "booster-seat", "created_at": "2025-05-28T09:12:00Z", "updated_at": "2025-06-01T14:22:31Z" } ] } ``` #### GET /organizations/{organization_id}/trips/{id}/ **Retrieve trip** Retrieve a single trip by ID. The response includes the trip's current status, its assignment (vehicle, driver, and attendants, once the provider assigns them), pricing, and full pickup and dropoff detail. Poll this endpoint to follow a trip through fulfillment. `driver_location` carries the last position the driver's device reported while working this trip. It is null before the driver sets off and for a while after the trip ends, so read `recorded_at` rather than assuming a coordinate is current. This is a convenience on a trip read rather than a tracking feed, and polling fast enough to animate a map will hit the rate limit. Parameters: - `id` (path, string (uuid), required): ID of the trip. - `organization_id` (path, string (uuid), required): ID of the organization. Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "assignment": { "vehicle": { "license_plate": "ABC123", "vin": "1XKEXAMPLE0000000", "make": "Toyota", "model": "Sienna", "year": 2022, "color": "Silver" }, "driver": { "id": "7d6e5f40-0000-4000-8000-000000000000", "first_name": "Jane", "last_name": "Doe" }, "attendants": null }, "driver_location": { "latitude": 40.712776, "longitude": -74.005974, "heading_degrees": 92.4, "speed_meters_per_second": 13.9, "accuracy_meters": 8.0, "recorded_at": "2025-06-01T14:30:00Z" }, "status": "assigned", "passenger": { "id": "d1f7c3e2-0b5a-4e6d-9c8b-1a2b3c4d5e6f", "first_name": "John", "last_name": "Doe", "dob": "1948-05-25", "email": "john.doe@example.com", "phone_number": "+12125550143" }, "payer": { "id": "9c8b7a65-4321-4dcb-a987-1234567890ab", "display_name": "Facility A" }, "external_trip_id": "ARHF-7890", "price_cents": 4500, "scheduled_pickup_at": "2025-06-01T14:30:00Z", "appointment_at": "2025-06-01T15:00:00Z", "pickup": { "full_address": "123 Main Street, Anytown, NY 10001", "number": "123", "street": "Main Street", "detail": "Apt 5B", "city": "Anytown", "state": "NY", "zip": "10001", "country": "United States", "latitude": 40.123456, "longitude": -74.123456, "num_stairs": 0, "contact_name": "John Doe", "contact_phone_number": "+12125550143", "driver_notes": "Ring the doorbell" }, "dropoff": { "full_address": "500 Medical Center Drive, Anytown, NY 10005", "number": "500", "street": "Medical Center Drive", "detail": "", "city": "Anytown", "state": "NY", "zip": "10005", "country": "United States", "latitude": 40.234567, "longitude": -74.234567, "num_stairs": 0, "contact_name": "Front Desk", "contact_phone_number": "+12125550170", "driver_notes": "Main entrance" }, "dispatcher_notes": "Passenger uses a folding wheelchair.", "estimated_distance_miles": 8.2, "is_will_call": false, "space_type": "wheelchair", "service_type": "curb-to-curb", "must_provide_wheelchair": true, "is_oxygen_required": false, "oxygen_liters_per_min": null, "num_attendants_needed": 0, "num_accompanying_passengers": 0, "has_infectious_disease": false, "seat_equipment": "booster-seat", "created_at": "2025-05-28T09:12:00Z", "updated_at": "2025-06-01T14:22:31Z" } ``` #### PATCH /organizations/{organization_id}/trips/{id}/ **Update trip** Partially update fields on an existing trip. All body fields are optional; omit a field to leave it unchanged. The trip's passenger is updated in place on the existing passenger record rather than reassigned to a different one. Updating a trip in a terminal state (canceled, completed, rejected) is not allowed. Parameters: - `id` (path, string (uuid), required): ID of the trip. - `organization_id` (path, string (uuid), required): ID of the organization. Request body example: ```json { "scheduled_pickup_at": "2025-06-01T15:00:00Z", "dispatcher_notes": "Passenger will wait in the main lobby." } ``` Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7" } ``` #### GET /organizations/{organization_id}/trips/{id}/events/ **List trip events** List the events recorded on a trip, oldest first and paginated. Each event carries when it occurred, where it was reported from, who performed it, and the vehicle's odometer reading where one is available. These are the trip's own events rather than a replay of the webhook stream. The two name overlapping facts differently, and the correspondence is not one to one. A single `event_type` here can come from several different transitions, and some webhook events have no trip event behind them at all. Read this list as the trip's own history rather than as something to reconcile against the deliveries you received. Parameters: - `id` (path, string (uuid), required): ID of the trip. - `organization_id` (path, string (uuid), required): ID of the organization. - `page` (query, integer, optional): A page number within the paginated result set. - `page_size` (query, integer, optional): Number of results to return per page. Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "count": 123, "next": "http://api.example.org/accounts/?page=4", "previous": "http://api.example.org/accounts/?page=2", "results": [ { "event_type": "status_at_pickup", "occurred_at": "2025-06-01T14:28:12Z", "latitude": 40.123456, "longitude": -74.123456, "odometer_meters": 154237.5, "actor": { "first_name": "Jane", "last_name": "Doe" } } ] } ``` #### POST /organizations/{organization_id}/trips/{id}/cancel/ **Cancel trip** Cancel a trip and record a reason from the supported set. A cancellation may incur a fee depending on timing and the provider's policy. To withdraw an offer the provider has not yet accepted, use retract instead, which assesses no fee. Parameters: - `id` (path, string (uuid), required): ID of the trip. - `organization_id` (path, string (uuid), required): ID of the organization. Request body example: ```json { "reason": "appointment canceled" } ``` Responses: - **400** - **403** - **404** - **429** - **200** #### POST /organizations/{organization_id}/trips/{id}/retract/ **Retract trip** Retract a trip offer the provider has not yet accepted or rejected, for example when the appointment it was booked for is no longer needed. The trip is removed. No cancellation or no-show fee is assessed, since the provider never committed to it. Only valid while the trip is in the `requested` state. Once the provider has accepted or rejected the offer the trip can no longer be retracted; use the cancel endpoint instead. The request takes no body. Parameters: - `id` (path, string (uuid), required): ID of the trip. - `organization_id` (path, string (uuid), required): ID of the organization. Responses: - **400** - **403** - **404** - **429** - **200** #### POST /organizations/{organization_id}/trips/{id}/activate_will_call/ **Activate will call trip** Activate a will-call trip so it can be scheduled, optionally setting the requested pickup time. If you omit `requested_pickup_at`, the current time is used. The requested time cannot be in the past. Parameters: - `id` (path, string (uuid), required): ID of the trip. - `organization_id` (path, string (uuid), required): ID of the organization. Request body example: ```json { "requested_pickup_at": "2025-06-01T17:00:00Z" } ``` Responses: - **400** - **403** - **404** - **429** - **200** ### Drivers The drivers on an organization's roster, so you can resolve the `driver_id` you receive on a trip or a webhook event to a person, and show your own view of the fleet. These endpoints are for partners reading their own organization, so they are open to customer partners only. A channel partner reads driver detail from the `assignment` on the trips it already has access to. #### GET /organizations/{organization_id}/drivers/ **List drivers** List the drivers on an organization's roster, paginated. A driver stays on the roster while they are out of rotation, so check `can_be_scheduled` rather than treating the list as who is available today. Available to customer partners only. A channel partner receives a `403` with the error code `customer_partner_only`, and reads driver detail from the `assignment` on the trip endpoints instead. Parameters: - `organization_id` (path, string (uuid), required): ID of the organization. - `page` (query, integer, optional): A page number within the paginated result set. - `page_size` (query, integer, optional): Number of results to return per page. Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "count": 123, "next": "http://api.example.org/accounts/?page=4", "previous": "http://api.example.org/accounts/?page=2", "results": [ { "id": "7d6e5f40-0000-4000-8000-000000000000", "first_name": "Jane", "last_name": "Doe", "email": "jane.doe@example.com", "phone_number": "+12125550143", "can_be_scheduled": true, "license": { "number": "D1234567", "state": "CA", "expiration_date": "2027-04-30", "dob": "1985-07-02" }, "created_at": "2025-05-28T09:12:00Z", "updated_at": "2025-06-04T11:41:00Z" } ] } ``` #### GET /organizations/{organization_id}/drivers/{id}/ **Retrieve driver** Retrieve a single driver by ID. This is how you resolve the `driver_id` on a webhook payload, or the `id` on a trip's `assignment.driver`, to a name, contact details, and license. Available to customer partners only. A channel partner receives a `403` with the error code `customer_partner_only`, and reads driver detail from the `assignment` on the trip endpoints instead. Parameters: - `id` (path, string (uuid), required): ID of the driver. - `organization_id` (path, string (uuid), required): ID of the organization. Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "id": "7d6e5f40-0000-4000-8000-000000000000", "first_name": "Jane", "last_name": "Doe", "email": "jane.doe@example.com", "phone_number": "+12125550143", "can_be_scheduled": true, "license": { "number": "D1234567", "state": "CA", "expiration_date": "2027-04-30", "dob": "1985-07-02" }, "created_at": "2025-05-28T09:12:00Z", "updated_at": "2025-06-04T11:41:00Z" } ``` ### Vehicles The vehicles in an organization's fleet, so you can resolve the `vehicle_id` you receive on a trip or a webhook event to a vehicle, and show your own view of the fleet. These endpoints are for partners reading their own organization, so they are open to customer partners only. A channel partner reads vehicle detail from the `assignment` on the trips it already has access to. #### GET /organizations/{organization_id}/vehicles/ **List vehicles** List the vehicles in an organization's fleet, paginated. A vehicle stays in the fleet while it is out of service, so check `can_be_scheduled` rather than treating the list as what is on the road today. Available to customer partners only. A channel partner receives a `403` with the error code `customer_partner_only`, and reads vehicle detail from the `assignment` on the trip endpoints instead. Parameters: - `organization_id` (path, string (uuid), required): ID of the organization. - `page` (query, integer, optional): A page number within the paginated result set. - `page_size` (query, integer, optional): Number of results to return per page. Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "count": 123, "next": "http://api.example.org/accounts/?page=4", "previous": "http://api.example.org/accounts/?page=2", "results": [ { "id": "3f2a1c80-0000-4000-8000-000000000000", "nickname": "Van 4", "make": "Toyota", "model": "Sienna", "year": 2020, "color": "White", "vin": "1FTBR1C89PKA12345", "license_plate": "ABC123", "license_plate_state": "CA", "category": "wheelchair", "can_be_scheduled": true, "notes": "Lift serviced quarterly", "created_at": "2025-05-28T09:12:00Z", "updated_at": "2025-06-04T11:41:00Z" } ] } ``` #### GET /organizations/{organization_id}/vehicles/{id}/ **Retrieve vehicle** Retrieve a single vehicle by ID. This is how you resolve the `vehicle_id` on a webhook payload, or the `id` on a trip's `assignment.vehicle`, to the vehicle's description and category. Available to customer partners only. A channel partner receives a `403` with the error code `customer_partner_only`, and reads vehicle detail from the `assignment` on the trip endpoints instead. Parameters: - `id` (path, string (uuid), required): ID of the vehicle. - `organization_id` (path, string (uuid), required): ID of the organization. Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "id": "3f2a1c80-0000-4000-8000-000000000000", "nickname": "Van 4", "make": "Toyota", "model": "Sienna", "year": 2020, "color": "White", "vin": "1FTBR1C89PKA12345", "license_plate": "ABC123", "license_plate_state": "CA", "category": "wheelchair", "can_be_scheduled": true, "notes": "Lift serviced quarterly", "created_at": "2025-05-28T09:12:00Z", "updated_at": "2025-06-04T11:41:00Z" } ``` ### Webhooks **Beta. This surface is in active development and may change, including breaking changes, without notice. Build against it with that in mind.** Register endpoints and Bambi posts events to them as trips change, so you can react without polling. Payloads carry ids, enums, and timestamps only, never PHI: fetch full details from the API using the ids in the event. Verify a delivery's signature before acting on it, treat `event_id` as an idempotency key, and order events by `occurred_at`. **Verifying a webhook delivery** in the introduction gives the signing scheme and a worked example. Deliveries arrive out of order routinely, including events on the same trip a few milliseconds apart. `occurred_at` carries microseconds so those still sort, which means keeping its full precision rather than truncating it to seconds. The test delivery is the one exception to the envelope. Its body is `{"success": true}`, with no `event_id` and no `event_type`, so a receiver that requires those fields rejects the first delivery it ever sees. Handle it or ignore it, and do not treat it as a malformed event. #### POST /webhooks/ **Register webhook endpoint** Register a URL to receive event notifications. Bambi delivers your account's events to every registered endpoint and signs each request so you can verify it came from Bambi. Use an HTTPS URL that returns a 2xx promptly and does its processing asynchronously. A URL must be unique within your account, and each account may register a limited number of endpoints. The response includes the signing secret, which is also retrievable later from the secret endpoint. Request body example: ```json { "url": "https://example.com/hooks/bambi" } ``` Responses: - **400** - **403** - **404** - **429** - **201** Response example: ```json { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "url": "https://example.com/hooks/bambi", "created_at": "2025-06-01T14:30:00Z", "is_disabled": false, "secret": "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw" } ``` #### GET /webhooks/ **List webhook endpoints** List the webhook endpoints registered for your account, ordered by creation time and paginated. Signing secrets are not included. Read a secret from the secret endpoint when you need it. Check `is_disabled` here if you have stopped receiving events. An endpoint that has been failing for five unbroken days stops receiving deliveries until you enable it again. Parameters: - `page` (query, integer, optional): A page number within the paginated result set. - `page_size` (query, integer, optional): Number of results to return per page. Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "count": 123, "next": "http://api.example.org/accounts/?page=4", "previous": "http://api.example.org/accounts/?page=2", "results": [ { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "url": "https://example.com/hooks/bambi", "created_at": "2025-06-01T14:30:00Z", "is_disabled": false } ] } ``` #### GET /webhooks/{id}/ **Retrieve webhook endpoint** Retrieve a single registered webhook endpoint by id. The signing secret is not included. Read it from the secret endpoint when you need it. An endpoint with `is_disabled` true has stopped receiving deliveries and will not resume on its own. Fix your receiver, then call the enable endpoint. Parameters: - `id` (path, string (uuid), required): ID of the webhook endpoint. Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "url": "https://example.com/hooks/bambi", "created_at": "2025-06-01T14:30:00Z", "is_disabled": true } ``` #### PATCH /webhooks/{id}/ **Update webhook endpoint URL** Change a registered endpoint's URL. The new URL must use HTTPS and be unique within your account. The change is pushed to the delivery service, so events flow to the new URL going forward. Parameters: - `id` (path, string (uuid), required): ID of the webhook endpoint. Request body example: ```json { "url": "https://example.com/hooks/bambi-v2" } ``` Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "url": "https://example.com/hooks/bambi-v2", "created_at": "2025-06-01T14:30:00Z", "is_disabled": false } ``` #### DELETE /webhooks/{id}/ **Delete webhook endpoint** Delete a registered webhook endpoint. Delivery to it stops and its URL becomes available to register again. Returns 204. Parameters: - `id` (path, string (uuid), required): ID of the webhook endpoint. Responses: - **400** - **403** - **404** - **429** - **204**: No response body #### GET /webhooks/{id}/secret/ **Retrieve signing secret** Retrieve the signing secret for an endpoint. Use it to verify that a delivery came from Bambi. The secret is also returned when the endpoint is registered; this is how you fetch it again later. Parameters: - `id` (path, string (uuid), required): ID of the webhook endpoint. Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "secret": "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw" } ``` #### POST /webhooks/{id}/secret/ **Rotate signing secret** Generate a new signing secret for an endpoint and return it. The previous secret keeps verifying deliveries for 24 hours, so update your receiver within that window. Rotating an endpoint more than ten times in that window returns 429 until an earlier secret expires. Parameters: - `id` (path, string (uuid), required): ID of the webhook endpoint. Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "secret": "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw" } ``` #### POST /webhooks/{id}/test/ **Send a test event** Deliver a signed test request to this endpoint, so you can confirm your receiver verifies the signature and answers 2xx before any trip activity depends on it. The body is `{"success": true}` and only this endpoint receives it. A 202 means Bambi queued the delivery, and your own logs are where the result shows up. Parameters: - `id` (path, string (uuid), required): ID of the webhook endpoint. Responses: - **400** - **403** - **404** - **429** - **202** Response example: ```json { "message_id": "msg_1srOrx2ZWZBpBUvZwXKQmoEYga2" } ``` #### POST /webhooks/{id}/enable/ **Enable webhook endpoint** Resume delivery to an endpoint that has been disabled, and return the endpoint with its new state. Bambi stops delivering to an endpoint after 120 hours in which every delivery failed. One success anywhere in that window resets the clock. The `is_disabled` field on any endpoint read tells you where you stand. The cutoff is a circuit breaker. A receiver that is refusing or timing out costs a full round of retries on every event, and that cost is paid by both sides indefinitely. Nothing here is automatic because we cannot tell when your receiver is fixed. Fix the receiver first and confirm it returns a 2xx, because a still-broken endpoint starts the clock again. Calling this on an endpoint that is already enabled succeeds and changes nothing. **Enabling does not redeliver what you missed.** Parameters: - `id` (path, string (uuid), required): ID of the webhook endpoint. Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "url": "https://example.com/hooks/bambi", "created_at": "2025-06-01T14:30:00Z", "is_disabled": false } ``` #### GET /webhooks/{id}/messages/ **List delivered messages** List the events Bambi sent to this endpoint, newest first, each with the status of its most recent delivery attempt and the exact payload that was sent. This is where you check whether an event you never handled was actually delivered. Paging is by cursor rather than page number. Read `next_cursor` from the response and pass it back as `cursor` until `done` is true. `prev_cursor` steps back toward newer rows through the same parameter. Bambi keeps 90 days of delivery history, and this call reads that window by default, so an empty page means nothing was delivered rather than that older events were lost. Parameters: - `after` (query, string (date-time), optional): Return only messages published after this time. - `before` (query, string (date-time), optional): Return only messages published before this time. - `cursor` (query, string, optional): The `next_cursor` from a previous page. Omit for the first page. - `delivery_status` (query, string, optional): Return only messages whose latest attempt has this status. - `event_types` (query, array, optional): Return only these event types. Repeat the parameter or comma-separate the values, Ex: `event_types=trip.completed&event_types=trip.unassigned` or `event_types=trip.completed,trip.unassigned`. A type that matches nothing returns an empty page rather than an error. - `id` (path, string (uuid), required): ID of the webhook endpoint. - `limit` (query, integer, optional): Rows per page, 1 to 250. Defaults to 50. - `trip_id` (query, string (uuid), optional): Return only messages about this trip, Ex: `9d5e1b7a-8c2f-4e3b-9a1d-6f7e8c9b0a1d`. Events that are not about a trip are never returned when this is set. Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "results": [ { "message_id": "msg_1srOrx2ZWZBpBUvZwXKQmoEYga2", "event_id": "018f3a1c-6c1e-7b3a-9f2e-2b8a4d5e6f70", "event_type": "trip.completed", "published_at": "2025-06-01T14:30:00Z", "delivery_status": "success", "next_attempt_at": null, "payload": { "event_id": "018f3a1c-6c1e-7b3a-9f2e-2b8a4d5e6f70", "event_type": "trip.completed", "occurred_at": "2025-06-01T14:29:58Z", "organization_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "data": { "trip_id": "9d5e1b7a-8c2f-4e3b-9a1d-6f7e8c9b0a1d" } } } ], "next_cursor": "msg_1srOrx2ZWZBpBUvZwXKQmoEYga2", "prev_cursor": "-msg_1srOrx2ZWZBpBUvZwXKQmoEYga2", "done": false } ``` #### GET /webhooks/{id}/messages/{message_id}/attempts/ **List delivery attempts for a message** List every attempt Bambi made to deliver one message to this endpoint, newest first, with the HTTP status and body your receiver returned each time. Use it to see why a delivery failed. Bambi retries a failing endpoint 8 times over roughly 28 hours, so a message that never landed has several attempts to read. Paging is by cursor rather than page number. Read `next_cursor` from the response and pass it back as `cursor` until `done` is true. `prev_cursor` steps back toward newer rows through the same parameter. Bambi keeps 90 days of delivery history, and this call reads that window by default, so an empty page means nothing was delivered rather than that older events were lost. Parameters: - `cursor` (query, string, optional): The `next_cursor` from a previous page. Omit for the first page. - `id` (path, string (uuid), required): ID of the webhook endpoint. - `limit` (query, integer, optional): Rows per page, 1 to 250. Defaults to 50. - `message_id` (path, string, required): ID of the message, either the `message_id` from the message list or the `event_id` Bambi published it under. Responses: - **400** - **403** - **404** - **429** - **200** Response example: ```json { "results": [ { "attempt_id": "atmpt_2tPqSy3aXaCqCVwaxYLRnpFZhb3", "message_id": "msg_1srOrx2ZWZBpBUvZwXKQmoEYga2", "delivery_status": "success", "response_status_code": 200, "response_body": "", "response_duration_ms": 142, "attempted_at": "2025-06-01T14:30:01Z", "trigger": "scheduled", "url": "https://example.com/hooks/bambi" }, { "attempt_id": "atmpt_1srOrx2ZWZBpBUvZwXKQmoEYga2", "message_id": "msg_1srOrx2ZWZBpBUvZwXKQmoEYga2", "delivery_status": "fail", "response_status_code": 503, "response_body": "upstream unavailable", "response_duration_ms": 87, "attempted_at": "2025-06-01T14:30:00Z", "trigger": "scheduled", "url": "https://example.com/hooks/bambi" } ], "next_cursor": null, "prev_cursor": "-atmpt_2tPqSy3aXaCqCVwaxYLRnpFZhb3", "done": true } ``` #### POST /webhooks/{id}/messages/{message_id}/resend/ **Resend a message** Queue one message for delivery to this endpoint again, for when your receiver was down or mishandled an event and you want it back. A 202 means Bambi queued the delivery, and the attempt shows up in this message's attempts with a `manual` trigger. This resends the one message you name. It does not replay everything that failed while your receiver was down. A message past the 90 day retention window can no longer be resent, because its payload is gone, and returns 400. Parameters: - `id` (path, string (uuid), required): ID of the webhook endpoint. - `message_id` (path, string, required): ID of the message, either the `message_id` from the message list or the `event_id` Bambi published it under. Responses: - **400** - **403** - **404** - **429** - **202** Response example: ```json { "message_id": "msg_1srOrx2ZWZBpBUvZwXKQmoEYga2" } ``` ## Webhooks ### trip.created Sent when a trip is created, whatever created it, including a dispatcher, a broker import, and this API itself. A trip created as an offer sends `trip.requested` instead of this. The fields here are for deciding whether the trip is yours to act on. Fetch the trip from the API with `trip_id` for everything else. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.created", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "status": "pending", "scheduled_pickup_at": "2026-06-11T15:30:00+00:00", "payer_id": "5e4d3c2b-0000-4000-8000-000000000000" } } ``` ### trip.requested Sent when a trip is offered to the organization and is waiting to be accepted or rejected. An offer withdrawn before either sends `trip.retracted`. The fields here are for deciding whether to take it. Fetch the trip from the API with `trip_id` for everything else, including where it goes and the space and service the passenger needs. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.requested", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "scheduled_pickup_at": "2026-06-11T15:30:00+00:00", "payer_id": "5e4d3c2b-0000-4000-8000-000000000000" } } ``` ### trip.retracted Sent when a requested trip is withdrawn by whoever offered it, which can happen any time before it is accepted or rejected. The trip is gone rather than canceled, so fetching it with `trip_id` returns a 404. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.retracted", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000" } } ``` ### trip.unassigned Sent when a trip is unassigned from its driver and returns to an unassigned state. Fetch the trip from the API with `trip_id` for its current details. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.unassigned", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "driver_id": "7d6e5f40-0000-4000-8000-000000000000", "vehicle_id": "1a2b3c4d-0000-4000-8000-000000000000" } } ``` ### trip.accepted Sent when a requested trip is accepted and joins the pool of work to be scheduled. No driver is assigned yet. Fetch the trip from the API with `trip_id` for its current details. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.accepted", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000" } } ``` ### trip.rejected Sent when a trip is rejected and will not be fulfilled. Most trips are rejected before anyone is assigned, so the two ids are usually null. Call the API with `trip_id` for the reason. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.rejected", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "driver_id": null, "vehicle_id": null } } ``` ### trip.unrejected Sent when a rejected trip is reinstated and is back in play. Treat it as a correction to an earlier `trip.rejected` and refetch the trip with `trip_id` for its current status. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.unrejected", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000" } } ``` ### trip.assigned Sent when a trip has a driver assigned to it. A reassignment sends this once, for the incoming driver. The two ids are a snapshot and a later in-place swap sends nothing, so refetch with `trip_id` when it matters. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.assigned", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "driver_id": "7d6e5f40-0000-4000-8000-000000000000", "vehicle_id": "1a2b3c4d-0000-4000-8000-000000000000" } } ``` ### trip.canceled Sent when a trip is canceled and will not be fulfilled. A dispatcher can type a free-form reason instead of choosing one, and those arrive as `other`. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.canceled", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "reason": "no show", "driver_id": "7d6e5f40-0000-4000-8000-000000000000", "vehicle_id": "1a2b3c4d-0000-4000-8000-000000000000" } } ``` ### trip.uncanceled Sent when a canceled trip is restored and is back in play. Treat it as a correction to an earlier `trip.canceled` and refetch the trip with `trip_id` for its current status. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.uncanceled", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "driver_id": "7d6e5f40-0000-4000-8000-000000000000", "vehicle_id": "1a2b3c4d-0000-4000-8000-000000000000" } } ``` ### trip.en_route Sent when the driver sets off toward the pickup location. Progress events are latest-wins rather than a strict sequence. Fetch the trip from the API with `trip_id` for its current details. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.en_route", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "latitude": 37.7749, "longitude": -122.4194, "location_accuracy": 12.5, "location_queried_at": "2026-06-10T11:59:58+00:00", "device_requested_at": "2026-06-10T12:00:00+00:00", "odometer": 48213.4, "speed": 11.2, "heading": 274.0, "driver_id": "7d6e5f40-0000-4000-8000-000000000000", "vehicle_id": "1a2b3c4d-0000-4000-8000-000000000000" } } ``` ### trip.at_pickup Sent when the driver arrives at the pickup location. Progress events are latest-wins rather than a strict sequence. Fetch the trip from the API with `trip_id` for its current details. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.at_pickup", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "latitude": 37.7749, "longitude": -122.4194, "location_accuracy": 12.5, "location_queried_at": "2026-06-10T11:59:58+00:00", "device_requested_at": "2026-06-10T12:00:00+00:00", "odometer": 48213.4, "speed": 11.2, "heading": 274.0, "driver_id": "7d6e5f40-0000-4000-8000-000000000000", "vehicle_id": "1a2b3c4d-0000-4000-8000-000000000000" } } ``` ### trip.transporting Sent when the passenger is on board and the trip is under way. Progress events are latest-wins rather than a strict sequence. Fetch the trip from the API with `trip_id` for its current details. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.transporting", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "latitude": 37.7749, "longitude": -122.4194, "location_accuracy": 12.5, "location_queried_at": "2026-06-10T11:59:58+00:00", "device_requested_at": "2026-06-10T12:00:00+00:00", "odometer": 48213.4, "speed": 11.2, "heading": 274.0, "driver_id": "7d6e5f40-0000-4000-8000-000000000000", "vehicle_id": "1a2b3c4d-0000-4000-8000-000000000000" } } ``` ### trip.at_dropoff Sent when the driver arrives at the dropoff location. Progress events are latest-wins rather than a strict sequence. Fetch the trip from the API with `trip_id` for its current details. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.at_dropoff", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "latitude": 37.7749, "longitude": -122.4194, "location_accuracy": 12.5, "location_queried_at": "2026-06-10T11:59:58+00:00", "device_requested_at": "2026-06-10T12:00:00+00:00", "odometer": 48213.4, "speed": 11.2, "heading": 274.0, "driver_id": "7d6e5f40-0000-4000-8000-000000000000", "vehicle_id": "1a2b3c4d-0000-4000-8000-000000000000" } } ``` ### trip.completed Sent when a trip reaches the completed status, either by the driver completing it or by a dispatcher marking it complete. Fetch the trip from the API with `trip_id` for its current details. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.completed", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "latitude": 37.7749, "longitude": -122.4194, "location_accuracy": 12.5, "location_queried_at": "2026-06-10T11:59:58+00:00", "device_requested_at": "2026-06-10T12:00:00+00:00", "odometer": 48213.4, "speed": 11.2, "heading": 274.0, "driver_id": "7d6e5f40-0000-4000-8000-000000000000", "vehicle_id": "1a2b3c4d-0000-4000-8000-000000000000" } } ``` ### trip.uncompleted Sent when a completed trip is reopened and is no longer complete. Treat it as a correction to an earlier `trip.completed` and refetch the trip with `trip_id` for its current status. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.uncompleted", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "driver_id": "7d6e5f40-0000-4000-8000-000000000000", "vehicle_id": "1a2b3c4d-0000-4000-8000-000000000000" } } ``` ### trip.will_call_activated Sent when a will-call trip is activated, meaning the passenger is ready and the trip now has a real pickup time instead of a placeholder. A will-call trip is booked without one because nobody knows when the appointment will end. Activation is the moment that time is known, so `scheduled_pickup_at` is the point of this event. It moves the pickup time without sending `trip.pickup_time_changed`, which reports a rescheduling rather than an activation. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.will_call_activated", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "scheduled_pickup_at": "2026-06-11T15:30:00+00:00", "driver_id": "7d6e5f40-0000-4000-8000-000000000000", "vehicle_id": "1a2b3c4d-0000-4000-8000-000000000000" } } ``` ### trip.will_call_deactivated Sent when a will-call activation is undone and the trip goes back to waiting on the passenger. Treat it as a correction to an earlier `trip.will_call_activated`. The trip keeps a pickup time so it still holds a place in the day, and on a trip with no driver that falls back to the end of the day, so `scheduled_pickup_at` is a placeholder again rather than a time anyone confirmed. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.will_call_deactivated", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "scheduled_pickup_at": "2026-06-11T23:59:00+00:00", "driver_id": "7d6e5f40-0000-4000-8000-000000000000", "vehicle_id": "1a2b3c4d-0000-4000-8000-000000000000" } } ``` ### trip.pickup_time_changed Sent when a trip is rescheduled to a different pickup time. Carries both times, so a partner holding the old one can tell this apart from a redelivery without refetching. Activating or deactivating a will-call trip also moves the pickup time and sends its own event instead of this one. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.pickup_time_changed", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "scheduled_pickup_at": "2026-06-11T15:30:00+00:00", "previous_pickup_at": "2026-06-11T14:00:00+00:00", "driver_id": "7d6e5f40-0000-4000-8000-000000000000", "vehicle_id": "1a2b3c4d-0000-4000-8000-000000000000" } } ``` ### trip.price_updated Sent when the price of a trip changes, whatever changed it, including a dispatcher editing it, a broker import, and the Partner API itself. This is the same amount the API returns as `price_cents`, and it carries both sides of the change so a partner holding the old one can tell this apart from a redelivery without refetching. Canceling a trip reprices it to zero or to a late-cancellation fee, and uncanceling restores it, so this can arrive alongside `trip.canceled` and `trip.uncanceled`. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.price_updated", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "price_cents": 12500, "previous_price_cents": 18000 } } ``` ### trip.address_changed Sent when a trip is moved to a different pickup or dropoff address. `leg` names the end that moved, and one event covers one end, so a trip whose pickup and dropoff both move in a single edit sends two. The address itself is never in the payload; fetch the trip from the API with `trip_id` for it. Distance and travel time are recalculated off the new address, so a partner holding an estimate should refetch. A new unit or suite at the same street address counts, since the driver is going somewhere else. Changing the contact, the stairs, or the notes for a leg describes the same place and sends nothing. Example payload: ```json { "event_id": "0f7e6d5c-0000-4000-8000-000000000000", "event_type": "trip.address_changed", "occurred_at": "2026-06-10T12:00:00+00:00", "organization_id": "8a7b6c5d-0000-4000-8000-000000000000", "data": { "trip_id": "3c2b1a09-0000-4000-8000-000000000000", "leg": "pickup" } } ``` ## Schemas Field-level detail for the request and response objects above. A type shown as another schema name refers to an object defined in this section. ### PartnersOAuthTokenRequest What a partner sends to exchange credentials for a token. - `client_id` (string, required) - `client_secret` (string, required) - `grant_type` (enum: `client_credentials`, required) ### PartnersOAuthTokenResponse - `access_token` (string, required) - `expires_in` (integer, required) - `token_type` (enum: `Bearer`, required) ### PaginatedPartnerOrganizationList - `count` (integer, required) - `next` (string (uri), optional) - `previous` (string (uri), optional) - `results` (array of PartnerOrganization, required) ### PaginatedPartnerPayerOrganizationList - `count` (integer, required) - `next` (string (uri), optional) - `previous` (string (uri), optional) - `results` (array of PartnerPayerOrganization, required) ### PartnerTripCreate - `passenger` (PartnerTripPassengerCreate, optional): A new passenger to create for the trip. Provide this or `passenger_id`, not both. - `passenger_id` (string (uuid), optional): The Bambi ID of an existing passenger, as returned in the `passenger.id` field of a trip. Provide this or `passenger`, not both. Ex: `123e4567-e89b-12d3-a456-426614174000` - `payer_id` (string (uuid), required): The ID of the payer, Ex: `123e4567-e89b-12d3-a456-426614174000` - `external_trip_id` (string, optional): The ID of the trip in the partner's system, Ex: `ARHF-7890` - `price_cents` (integer, optional): The price of the trip in cents, Ex: `10000` - `scheduled_pickup_at` (string (date-time), required): The scheduled pickup datetime in UTC, Ex: `2025-01-01T00:00:00Z` - `appointment_at` (string (date-time), optional): The datetime of the passenger's appointment in UTC, Ex: `2025-01-01T00:00:00Z` - `pickup` (PartnerTripLocationDetailCreate, required): The pickup location for the trip - `dropoff` (PartnerTripLocationDetailCreate, required): The dropoff location for the trip - `dispatcher_notes` (string, optional): The dispatcher notes for the trip, Ex: `Please call the passenger to confirm the pickup` - `is_will_call` (boolean, optional): Whether the trip is a will call trip, Ex: `true` - `space_type` (enum: `wheelchair`, `wheelchair xl`, `broda chair`, `geri chair`, `stretcher`, `stretcher xl`, `ambulatory`, `delivery`, required): The space type required for the trip, Ex: `wheelchair` - `service_type` (enum: `curb-to-curb`, `door-to-door`, `door-through-door`, `person-to-person`, required): The service type required for the trip, Ex: `curb-to-curb` - `must_provide_wheelchair` (boolean, optional): Whether a wheelchair must be provided to the passenger, Ex: `true` - `is_oxygen_required` (boolean, optional): Whether oxygen must be provided to the passenger, Ex: `true` - `oxygen_liters_per_min` (number (double), optional): The amount of oxygen required for the trip in liters per minute, Ex: `2.5` - `num_attendants_needed` (integer, optional): The number of attendants needed for the trip, Ex: `2` - `num_accompanying_passengers` (integer, optional): The number of accompanying passengers for the trip, Ex: `1` - `has_infectious_disease` (boolean, optional): Whether the passenger has an infectious disease, Ex: `true` - `seat_equipment` (enum: `booster-seat`, `car-seat`, optional): The seat equipment required for the trip, Ex: `booster-seat` ### PartnerTripId The body a trip write answers with, which is the id and nothing else. - `id` (string (uuid), required): The ID of the trip in Bambi, Ex: `123e4567-e89b-12d3-a456-426614174000` ### PaginatedPartnerTripReadList - `count` (integer, required) - `next` (string (uri), optional) - `previous` (string (uri), optional) - `results` (array of PartnerTripRead, required) ### PartnerTripRead - `id` (string (uuid), required): The ID of the trip, Ex: `123e4567-e89b-12d3-a456-426614174000` - `assignment` (PartnerTripAssignment, required): The vehicle, driver, and attendants for the trip - `driver_location` (PartnerTripDriverLocation, required): Where the driver was last reported to be on this trip - `status` (enum: `requested`, `pending`, `assigned`, `en route`, `at pickup`, `transporting`, `at dropoff`, `completed`, `canceled`, `rejected`, required): The status of the trip, Ex: `completed` - `passenger` (PartnerTripPassenger, required): The passenger for the trip - `payer` (PartnerTripPayer, required): The payer for the trip - `external_trip_id` (string, required): The external trip ID, Ex: `ARHF-7890` - `price_cents` (integer, required): The price of the trip in cents. Ex: `10000`. Null when the trip has no price - `scheduled_pickup_at` (string (date-time), required): The scheduled pickup datetime in UTC for the trip, Ex: `2025-01-01T00:00:00Z` - `appointment_at` (string (date-time), required): The datetime of the passenger's appointment in UTC, Ex: `2025-01-01T00:00:00Z`. Null when the trip has no appointment - `pickup` (PartnerTripLocationDetail, required): The pickup location for the trip - `dropoff` (PartnerTripLocationDetail, required): The dropoff location for the trip - `dispatcher_notes` (string, required): The dispatcher notes for the trip, Ex: `Please call the passenger to confirm the pickup` - `estimated_distance_miles` (number (double), required): The estimated distance of the trip in miles, Ex: `10.5`. Null when no estimate has been made - `is_will_call` (boolean, required): Whether the trip is a will call trip, Ex: `true` - `space_type` (enum: `wheelchair`, `wheelchair xl`, `broda chair`, `geri chair`, `stretcher`, `stretcher xl`, `ambulatory`, `delivery`, required): The space type required for the trip, Ex: `wheelchair` - `service_type` (enum: `curb-to-curb`, `door-to-door`, `door-through-door`, `person-to-person`, required): The service type required for the trip, Ex: `curb-to-curb` - `must_provide_wheelchair` (boolean, required): Whether the trip must provide a wheelchair, Ex: `true` - `is_oxygen_required` (boolean, required): Whether the trip requires oxygen, Ex: `true` - `oxygen_liters_per_min` (number (double), required): The amount of oxygen required for the trip in liters per minute, Ex: `2.5`. Null when no rate is recorded - `num_attendants_needed` (integer, required): The number of attendants needed for the trip, Ex: `2` - `num_accompanying_passengers` (integer, required): The number of accompanying passengers for the trip, Ex: `1` - `has_infectious_disease` (boolean, required): Whether the passenger has an infectious disease, Ex: `true` - `seat_equipment` (enum: `booster-seat`, `car-seat`, required): The seat equipment required for the trip, Ex: `booster-seat`. Empty when the trip needs none - `created_at` (string (date-time), required): The datetime the trip was created in UTC, Ex: `2025-01-01T00:00:00Z` - `updated_at` (string (date-time), required): The datetime the trip last changed in UTC, Ex: `2025-01-01T00:00:00Z`. The trip list filters on this value, and its description covers how to poll with it. ### PatchedPartnerTripPartialUpdate - `passenger` (PartnerTripPassengerPartialUpdate, optional): Fields to update on the trip's existing passenger record. All sub-fields are optional. Updates the passenger in place and may affect other trips that reference the same passenger. - `payer_id` (string (uuid), optional): The ID of the payer, Ex: `123e4567-e89b-12d3-a456-426614174000` - `external_trip_id` (string, optional): The ID of the trip in the partner's system, Ex: `ARHF-7890` - `price_cents` (integer, optional): The price of the trip in cents, Ex: `10000` - `scheduled_pickup_at` (string (date-time), optional): The scheduled pickup datetime in UTC, Ex: `2025-01-01T00:00:00Z` - `appointment_at` (string (date-time), optional): The datetime of the passenger's appointment in UTC, Ex: `2025-01-01T00:00:00Z` - `pickup` (PartnerTripLocationDetailCreate, optional): The pickup location for the trip - `dropoff` (PartnerTripLocationDetailCreate, optional): The dropoff location for the trip - `dispatcher_notes` (string, optional): The dispatcher notes for the trip, Ex: `Please call the passenger to confirm the pickup`. Send an empty string to clear the free-form tail while keeping the address-derived `Bambi Note: ...` lines intact. If a dispatcher has reshaped the notes via the internal webapp and the `Bambi Note:` prefix is no longer present, the whole field is treated as opaque and an empty string clears it entirely. - `is_will_call` (boolean, optional): Whether the trip is a will call trip, Ex: `true` - `space_type` (enum: `wheelchair`, `wheelchair xl`, `broda chair`, `geri chair`, `stretcher`, `stretcher xl`, `ambulatory`, `delivery`, optional): The space type required for the trip, Ex: `wheelchair` - `service_type` (enum: `curb-to-curb`, `door-to-door`, `door-through-door`, `person-to-person`, optional): The service type required for the trip, Ex: `curb-to-curb` - `must_provide_wheelchair` (boolean, optional): Whether a wheelchair must be provided to the passenger, Ex: `true` - `is_oxygen_required` (boolean, optional): Whether oxygen must be provided to the passenger, Ex: `true` - `oxygen_liters_per_min` (number (double), optional): The amount of oxygen required for the trip in liters per minute, Ex: `2.5` - `num_attendants_needed` (integer, optional): The number of attendants needed for the trip, Ex: `2` - `num_accompanying_passengers` (integer, optional): The number of accompanying passengers for the trip, Ex: `1` - `has_infectious_disease` (boolean, optional): Whether the passenger has an infectious disease, Ex: `true` - `seat_equipment` (enum: `booster-seat`, `car-seat`, optional): The seat equipment required for the trip, Ex: `booster-seat` ### PaginatedPartnerTripEventList - `count` (integer, required) - `next` (string (uri), optional) - `previous` (string (uri), optional) - `results` (array of PartnerTripEvent, required) ### PartnerTripCancel - `reason` (enum: `no show`, `passenger not ready`, `passenger refused`, `passenger unable`, `scheduling conflict`, `appointment canceled`, `user requested`, `payer canceled`, `other`, required): The reason for canceling the trip, Ex: `appointment canceled` ### PartnerTripActivateWillCall - `requested_pickup_at` (string (date-time), optional): The new requested pickup time for the trip, Ex: `2025-01-01T00:00:00Z`. If not provided, defaults to the current time ### PaginatedPartnerDriverList - `count` (integer, required) - `next` (string (uri), optional) - `previous` (string (uri), optional) - `results` (array of PartnerDriver, required) ### PartnerDriver A driver on the organization's roster. - `id` (string (uuid), required): The Bambi ID of the driver, Ex: `123e4567-e89b-12d3-a456-426614174000` - `first_name` (string, required): The first name of the driver, Ex: `John` - `last_name` (string, required): The last name of the driver, Ex: `Doe` - `email` (string (email), required): The email of the driver, Ex: `john.doe@example.com` - `phone_number` (string, required): The phone number of the driver, Ex: `+12125550143`, or `null` if they have none on file - `can_be_scheduled` (boolean, required): Whether the driver is available to be put on trips. A driver who is on leave or otherwise out of rotation stays on the roster with this set to `false` - `license` (PartnerDriverLicense, required): The driver's active license, or `null` if they have none on file - `created_at` (string (date-time), required): When the driver was added, Ex: `2025-01-01T00:00:00Z` - `updated_at` (string (date-time), required): When the driver was last changed, Ex: `2025-01-01T00:00:00Z`. Poll this to pick up roster changes without diffing the whole list ### PaginatedPartnerVehicleList - `count` (integer, required) - `next` (string (uri), optional) - `previous` (string (uri), optional) - `results` (array of PartnerVehicle, required) ### PartnerVehicle A vehicle in the organization's fleet. - `id` (string (uuid), required): The Bambi ID of the vehicle, Ex: `123e4567-e89b-12d3-a456-426614174000` - `nickname` (string, required): What the organization calls this vehicle day to day, Ex: `Van 4`. Unique within the organization - `make` (string, required): The make of the vehicle, Ex: `Toyota` - `model` (string, required): The model of the vehicle, Ex: `Sienna` - `year` (integer, required): The model year of the vehicle, Ex: `2020` - `color` (string, required): The color of the vehicle, Ex: `White` - `vin` (string, required): The VIN of the vehicle, Ex: `1FTBR1C89PKA12345` - `license_plate` (string, required): The license plate of the vehicle, Ex: `ABC123` - `license_plate_state` (string, required): The state the license plate is registered in, Ex: `CA` - `category` (enum: `wheelchair`, `stretcher`, `ambulatory`, required): The kind of transport the vehicle is equipped for, Ex: `wheelchair` - `can_be_scheduled` (boolean, required): Whether the vehicle is available to be put on trips. A vehicle that is out of service stays in the fleet with this set to `false` - `notes` (string, required): Free-text notes the organization keeps on the vehicle, Ex: `Lift serviced quarterly`. Empty when there are none - `created_at` (string (date-time), required): When the vehicle was added, Ex: `2025-01-01T00:00:00Z` - `updated_at` (string (date-time), required): When the vehicle was last changed, Ex: `2025-01-01T00:00:00Z`. Poll this to pick up fleet changes without diffing the whole list ### PartnerWebhookRegister The body that registers or moves an endpoint, which is the URL alone. - `url` (string (uri), required): The HTTPS URL Bambi delivers events to, Ex: `https://example.com/hooks/bambi` ### PartnerWebhookCreated Register response. Carries the signing secret, which the retrieve and list responses omit so a plain read never returns secrets. - `id` (string (uuid), required): The ID of the webhook endpoint, Ex: `123e4567-e89b-12d3-a456-426614174000` - `url` (string (uri), required): The HTTPS URL Bambi delivers events to, Ex: `https://example.com/hooks/bambi` - `created_at` (string (date-time), required): When the endpoint was registered, Ex: `2025-06-01T14:30:00Z` - `is_disabled` (boolean, required): Whether Bambi has stopped delivering events to this endpoint, Ex: `false`. Becomes `true` after 120 hours in which every delivery failed; a single success resets that clock. Call the enable endpoint once your receiver is healthy again. Null when the state cannot be determined, for example when the delivery service is unreachable. - `secret` (string, required): The signing secret used to verify event deliveries, Ex: `whsec_...`. Returned when the endpoint is registered and retrievable later from the secret endpoint. Store it securely. ### PaginatedPartnerWebhookList - `count` (integer, required) - `next` (string (uri), optional) - `previous` (string (uri), optional) - `results` (array of PartnerWebhook, required) ### PartnerWebhook - `id` (string (uuid), required): The ID of the webhook endpoint, Ex: `123e4567-e89b-12d3-a456-426614174000` - `url` (string (uri), required): The HTTPS URL Bambi delivers events to, Ex: `https://example.com/hooks/bambi` - `created_at` (string (date-time), required): When the endpoint was registered, Ex: `2025-06-01T14:30:00Z` - `is_disabled` (boolean, required): Whether Bambi has stopped delivering events to this endpoint, Ex: `false`. Becomes `true` after 120 hours in which every delivery failed; a single success resets that clock. Call the enable endpoint once your receiver is healthy again. Null when the state cannot be determined, for example when the delivery service is unreachable. ### PatchedPartnerWebhook - `id` (string (uuid), optional): The ID of the webhook endpoint, Ex: `123e4567-e89b-12d3-a456-426614174000` - `url` (string (uri), optional): The HTTPS URL Bambi delivers events to, Ex: `https://example.com/hooks/bambi` - `created_at` (string (date-time), optional): When the endpoint was registered, Ex: `2025-06-01T14:30:00Z` - `is_disabled` (boolean, optional): Whether Bambi has stopped delivering events to this endpoint, Ex: `false`. Becomes `true` after 120 hours in which every delivery failed; a single success resets that clock. Call the enable endpoint once your receiver is healthy again. Null when the state cannot be determined, for example when the delivery service is unreachable. ### PartnerWebhookSecret - `secret` (string, required): The signing secret used to verify event deliveries, Ex: `whsec_...`. Store it securely. ### PartnerWebhookTest - `message_id` (string, required): ID of the queued test delivery, Ex: `msg_1srOrx2ZWZBpBUvZwXKQmoEYga2`. Quote it when asking support about a test. ### PartnerWebhookEnable Enable response. Takes no input, so a POST cannot change anything beyond resuming delivery. - `id` (string (uuid), required): The ID of the webhook endpoint, Ex: `123e4567-e89b-12d3-a456-426614174000` - `url` (string (uri), required): The HTTPS URL Bambi delivers events to, Ex: `https://example.com/hooks/bambi` - `created_at` (string (date-time), required): When the endpoint was registered, Ex: `2025-06-01T14:30:00Z` - `is_disabled` (boolean, required): Whether Bambi has stopped delivering events to this endpoint, Ex: `false`. Becomes `true` after 120 hours in which every delivery failed; a single success resets that clock. Call the enable endpoint once your receiver is healthy again. Null when the state cannot be determined, for example when the delivery service is unreachable. ### PartnerWebhookMessagePage A page of messages delivered to one endpoint. - `results` (array of PartnerWebhookMessage, required) - `next_cursor` (string, required): Pass as `cursor` to fetch the next page. Null on the last page, so read this rather than counting pages. - `prev_cursor` (string, required): Pass as `cursor` to step back toward newer rows. Both directions use the same parameter, since the direction is encoded in the value. - `done` (boolean, required): True when this is the last page. ### PartnerWebhookAttemptPage A page of delivery attempts against one message. - `results` (array of PartnerWebhookAttempt, required) - `next_cursor` (string, required): Pass as `cursor` to fetch the next page. Null on the last page, so read this rather than counting pages. - `prev_cursor` (string, required): Pass as `cursor` to step back toward newer rows. Both directions use the same parameter, since the direction is encoded in the value. - `done` (boolean, required): True when this is the last page. ### PartnerWebhookResend Owns the resend write, so the action stays a verb. Takes no input, since the message to resend comes from the URL. - `message_id` (string, required): ID of the message queued for redelivery, Ex: `msg_1srOrx2ZWZBpBUvZwXKQmoEYga2`. Quote it when asking support about a redelivery. ### TripCreatedWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripCreatedWebhookPayload, required) ### TripRequestedWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripRequestedWebhookPayload, required) ### TripRetractedWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripRetractedWebhookPayload, required) ### TripUnassignedWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripUnassignedWebhookPayload, required) ### TripAcceptedWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripAcceptedWebhookPayload, required) ### TripRejectedWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripRejectedWebhookPayload, required) ### TripUnrejectedWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripUnrejectedWebhookPayload, required) ### TripAssignedWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripAssignedWebhookPayload, required) ### TripCanceledWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripCanceledWebhookPayload, required) ### TripUncanceledWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripUncanceledWebhookPayload, required) ### TripEnRouteWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripEnRouteWebhookPayload, required) ### TripAtPickupWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripAtPickupWebhookPayload, required) ### TripTransportingWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripTransportingWebhookPayload, required) ### TripAtDropoffWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripAtDropoffWebhookPayload, required) ### TripCompletedWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripCompletedWebhookPayload, required) ### TripUncompletedWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripUncompletedWebhookPayload, required) ### TripWillCallActivatedWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripWillCallActivatedWebhookPayload, required) ### TripWillCallDeactivatedWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripWillCallDeactivatedWebhookPayload, required) ### TripPickupTimeChangedWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripPickupTimeChangedWebhookPayload, required) ### TripPriceUpdatedWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripPriceUpdatedWebhookPayload, required) ### TripAddressChangedWebhookEnvelope Common envelope wrapping every webhook event; `data` holds the event-specific payload. - `event_id` (string (uuid), required): Unique id for this event. Use it as an idempotency key; a redelivery reuses the same id. - `event_type` (string, required): The event type, e.g. "trip.unassigned". - `occurred_at` (string (date-time), required): UTC time the event occurred. Order events by this field. - `organization_id` (string (uuid), required): ID of the organization the event belongs to. - `data` (TripAddressChangedWebhookPayload, required) ### PartnerOrganization - `id` (string (uuid), required): The ID of the organization, Ex: `123e4567-e89b-12d3-a456-426614174000` - `name` (string, required): The name of the organization, Ex: `Safe Transport` ### PartnerPayerOrganization - `id` (string (uuid), required): The ID of the payer, Ex: `123e4567-e89b-12d3-a456-426614174000` - `display_name` (string, required): The display name of the payer, Ex: `Facility A` ### PartnerTripPassengerCreate - `first_name` (string, required): The first name of the passenger, Ex: `John` - `last_name` (string, required): The last name of the passenger, Ex: `Doe` - `dob` (string (date), required): The date of birth of the passenger, Ex: `1990-01-01` - `email` (string (email), optional): The email of the passenger, Ex: `john.doe@example.com` - `phone_number` (string, optional): The phone number of the passenger, Ex: `+12125550143` ### PartnerTripLocationDetailCreate - `number` (string, required): The number of the address, Ex: `4500` - `street` (string, required): The street of the address, Ex: `Main Street` - `detail` (string, optional): The detail of the address, Ex: `Apt 5B` - `city` (string, required): The city of the address, Ex: `New York` - `state` (string, required): The state of the address, Ex: `New York` - `zip` (string, required): The zip code of the address, Ex: `10001` - `country` (string, required): The country of the address, Ex: `United States` - `latitude` (number (double), optional): The latitude of the address, Ex: `40.712776` - `longitude` (number (double), optional): The longitude of the address, Ex: `-74.005974` - `driver_notes` (string, optional): The driver notes for the address, Ex: `Please ring the doorbell` - `num_stairs` (integer, optional): The number of stairs at the address, Ex: `2` - `contact_name` (string, optional): The name of the contact at the address, Ex: `John Doe` - `contact_phone_number` (string, optional): The phone number of the contact at the address, Ex: `+12125550143` ### PartnerTripAssignment - `vehicle` (PartnerTripAssignmentVehicle, required): The vehicle assigned to the trip. Null when none is assigned - `driver` (PartnerTripAssignmentDriver, required): The driver assigned to the trip. Null when none is assigned - `attendants` (array of PartnerTripAssignmentAttendants, required): The attendants assigned to the trip. Empty when there are none ### PartnerTripDriverLocation The last position the driver's device reported on this trip. - `latitude` (number (double), required): The latitude of the position, Ex: `40.712776` - `longitude` (number (double), required): The longitude of the position, Ex: `-74.005974` - `heading_degrees` (number (double), required): The direction of travel in degrees clockwise from north, Ex: `92.4`. Null when the position did not come from GPS. - `speed_meters_per_second` (number (double), required): The speed of travel in meters per second, Ex: `13.9`. Null when the position did not come from GPS. - `accuracy_meters` (number (double), required): The radius of uncertainty around the position in meters, Ex: `8.0`. Null when the position did not come from GPS. - `recorded_at` (string (date-time), required): When the device recorded the position, Ex: `2025-06-01T14:30:00Z`. Read this before acting on the coordinates, because a driver in a tunnel or with the app closed keeps reporting the last position they had ### PartnerTripPassenger - `id` (string (uuid), required): The Bambi ID of the passenger, Ex: `123e4567-e89b-12d3-a456-426614174000` - `first_name` (string, required): The first name of the passenger, Ex: `John` - `last_name` (string, required): The last name of the passenger, Ex: `Doe` - `dob` (string (date), required): The date of birth of the passenger, Ex: `1990-01-01`. Null when unknown - `email` (string (email), required): The email of the passenger, Ex: `john.doe@example.com`. Null when unknown - `phone_number` (string, required): The phone number of the passenger, Ex: `+12125550143`. Null when unknown ### PartnerTripPayer - `id` (string (uuid), required): The ID of the payer, Ex: `123e4567-e89b-12d3-a456-426614174000` - `display_name` (string, required): The display name of the payer, Ex: `Facility A` ### PartnerTripLocationDetail - `full_address` (string, required): The full street address, Ex: `4500 Broadway, New York, NY 10001` - `number` (string, required): The number of the address, Ex: `4500` - `street` (string, required): The street of the address, Ex: `Broadway` - `detail` (string, required): The detail of the address, Ex: `Apt 5B` - `city` (string, required): The city of the address, Ex: `New York` - `state` (string, required): The state of the address, Ex: `New York` - `zip` (string, required): The zip code of the address, Ex: `10001` - `country` (string, required): The country of the address, Ex: `United States` - `latitude` (number (double), required): The latitude of the address, Ex: `40.712776` - `longitude` (number (double), required): The longitude of the address, Ex: `-74.005974` - `num_stairs` (integer, required): The number of stairs at the address, Ex: `2` - `contact_name` (string, required): The name of the contact at the address, Ex: `John Doe` - `contact_phone_number` (string, required): The phone number of the contact at the address, Ex: `+12125550143`. Null when there is none - `driver_notes` (string, required): The driver notes for the address, Ex: `Please ring the doorbell` ### PartnerTripPassengerPartialUpdate - `first_name` (string, optional): The first name of the passenger, Ex: `John` - `last_name` (string, optional): The last name of the passenger, Ex: `Doe` - `dob` (string (date), optional): The date of birth of the passenger, Ex: `1990-01-01` - `email` (string (email), optional): The email of the passenger, Ex: `john.doe@example.com` - `phone_number` (string, optional): The phone number of the passenger, Ex: `+12125550143` ### PartnerTripEvent - `event_type` (enum: `status_en_route`, `status_at_pickup`, `status_transporting`, `status_at_dropoff`, `completion`, `uncompletion`, `cancellation`, `uncancellation`, `accept`, `assign`, `unassign`, `lock`, `unlock`, `rejection`, `unrejection`, `retraction`, `activate_will_call`, `update_pickup_at`, `push_needs_at_pickup`, `push_needs_transporting`, `push_needs_dropoff`, `push_needs_completed`, `enter_pickup_geofence`, `exit_pickup_geofence`, `enter_dropoff_geofence`, `exit_dropoff_geofence`, `cancel_will_call_activation`, `cancellation_request`, `accept_cancellation_request`, `reject_cancellation_request`, `remove_cancellation_request`, required): What the event records, Ex: `status_at_pickup` - `occurred_at` (string (date-time), required): When the event occurred in UTC, Ex: `2025-01-01T00:00:00Z` - `latitude` (number (double), required): The latitude the event was reported from, Ex: `40.123456`. Null when no location was reported, which is normal for an action taken from the web app. - `longitude` (number (double), required): The longitude the event was reported from, Ex: `-74.123456`. Null when no location was reported, which is normal for an action taken from the web app. - `odometer_meters` (number (double), required): The vehicle's odometer reading in meters, Ex: `154237.5`. Null when the driver's device did not report one. - `actor` (PartnerTripEventActor, required): The person who performed the action. The driver on the progress events and a dispatcher on the others. ### PartnerDriverLicense The driver's active license. - `number` (string, required): The license number, Ex: `D1234567` - `state` (string, required): The state on the license, Ex: `CA` - `expiration_date` (string (date), required): The date the license expires, Ex: `2027-04-30` - `dob` (string (date), required): The driver's date of birth, Ex: `1985-07-02` ### PartnerWebhookMessage A message Bambi sent, plus the status of its latest attempt. - `message_id` (string, required): ID of the message, Ex: `msg_1srOrx2ZWZBpBUvZwXKQmoEYga2`. Use it to read the delivery attempts for this message. - `event_id` (string, required): The `event_id` from the delivered payload, Ex: `018f3a1c-6c1e-7b3a-9f2e-2b8a4d5e6f70`. This is the value your receiver dedups on, so it is how you match a row here to an event you handled. - `event_type` (string, required): The event type, Ex: `trip.completed`. - `published_at` (string (date-time), required): When Bambi published the message, Ex: `2025-06-01T14:30:00Z`. The payload's own `occurred_at` is when the underlying change happened. - `delivery_status` (enum: `success`, `fail`, `sending`, required): Delivery status of the latest attempt. `success` means your endpoint answered 2xx, `fail` means every attempt was exhausted, and `sending` means another retry is scheduled. - `next_attempt_at` (string (date-time), required): When the next retry is scheduled, Ex: `2025-06-01T14:35:00Z`. Null unless the message is still being retried. - `payload` (required): The exact body Bambi sent, envelope included. ### PartnerWebhookAttempt One delivery attempt, with the response the receiver returned. - `attempt_id` (string, required): ID of the attempt, Ex: `atmpt_1srOrx2ZWZBpBUvZwXKQmoEYga2`. - `message_id` (string, required): ID of the message this attempt delivered. - `delivery_status` (enum: `success`, `fail`, required): Outcome of this individual attempt. `success` means your endpoint answered 2xx and `fail` means it did not. A message that is still being retried reports `sending`, and its attempts so far report `fail`. - `response_status_code` (integer, required): HTTP status your endpoint returned, Ex: `200`. A `0` means Bambi never got a response, from a timeout, a refused connection or a TLS failure. - `response_body` (string, required): The body your endpoint returned, truncated if long. - `response_duration_ms` (integer, required): How long your endpoint took to respond, in milliseconds, Ex: `142`. - `attempted_at` (string (date-time), required): When the attempt was made, Ex: `2025-06-01T14:30:01Z`. - `trigger` (enum: `scheduled`, `manual`, required): `scheduled` for a delivery Bambi made on its own, including automatic retries. `manual` for one you asked to be resent. - `url` (string (uri), required): The URL this attempt was delivered to. It can differ from the endpoint's current URL if the URL was updated after the attempt. ### TripCreatedWebhookPayload Sent when a trip is created, whatever created it, including a dispatcher, a broker import, and this API itself. A trip created as an offer sends `trip.requested` instead of this. The fields here are for deciding whether the trip is yours to act on. Fetch the trip from the API with `trip_id` for everything else. - `trip_id` (string (uuid), required): ID of the trip that was created. - `status` (enum: `requested`, `pending`, `assigned`, `en route`, `at pickup`, `transporting`, `at dropoff`, `completed`, `canceled`, `rejected`, required): The status the trip was created in. An import can create one that is already assigned or already finished. - `scheduled_pickup_at` (string (date-time), required): When the trip is scheduled for pickup, as of creation. A later reschedule sends no event, so refetch when the time matters. - `payer_id` (string (uuid), required): ID of the payer for the trip. ### TripRequestedWebhookPayload Sent when a trip is offered to the organization and is waiting to be accepted or rejected. An offer withdrawn before either sends `trip.retracted`. The fields here are for deciding whether to take it. Fetch the trip from the API with `trip_id` for everything else, including where it goes and the space and service the passenger needs. - `trip_id` (string (uuid), required): ID of the trip that was requested. - `scheduled_pickup_at` (string (date-time), required): When the trip is scheduled for pickup, as of the offer. A later reschedule sends no event, so refetch when the time matters. - `payer_id` (string (uuid), required): ID of the payer for the trip. ### TripRetractedWebhookPayload Sent when a requested trip is withdrawn by whoever offered it, which can happen any time before it is accepted or rejected. The trip is gone rather than canceled, so fetching it with `trip_id` returns a 404. - `trip_id` (string (uuid), required): ID of the trip that was withdrawn. ### TripUnassignedWebhookPayload Sent when a trip is unassigned from its driver and returns to an unassigned state. Fetch the trip from the API with `trip_id` for its current details. - `trip_id` (string (uuid), required): ID of the trip that was unassigned. - `driver_id` (string (uuid), required): ID of the driver on the trip, or null if it has none. - `vehicle_id` (string (uuid), required): ID of the vehicle on the trip, or null if it has none. ### TripAcceptedWebhookPayload Sent when a requested trip is accepted and joins the pool of work to be scheduled. No driver is assigned yet. Fetch the trip from the API with `trip_id` for its current details. - `trip_id` (string (uuid), required): ID of the trip that was accepted. ### TripRejectedWebhookPayload Sent when a trip is rejected and will not be fulfilled. Most trips are rejected before anyone is assigned, so the two ids are usually null. Call the API with `trip_id` for the reason. - `trip_id` (string (uuid), required): ID of the trip that was rejected. - `driver_id` (string (uuid), required): ID of the driver the trip was on, or null if it had none. - `vehicle_id` (string (uuid), required): ID of the vehicle the trip was on, or null if it had none. ### TripUnrejectedWebhookPayload Sent when a rejected trip is reinstated and is back in play. Treat it as a correction to an earlier `trip.rejected` and refetch the trip with `trip_id` for its current status. - `trip_id` (string (uuid), required): ID of the trip that was reinstated. ### TripAssignedWebhookPayload Sent when a trip has a driver assigned to it. A reassignment sends this once, for the incoming driver. The two ids are a snapshot and a later in-place swap sends nothing, so refetch with `trip_id` when it matters. - `trip_id` (string (uuid), required): ID of the trip that was assigned. - `driver_id` (string (uuid), required): ID of the driver now on the trip, or null if it has none. - `vehicle_id` (string (uuid), required): ID of the vehicle now on the trip, or null if it has none. ### TripCanceledWebhookPayload Sent when a trip is canceled and will not be fulfilled. A dispatcher can type a free-form reason instead of choosing one, and those arrive as `other`. - `trip_id` (string (uuid), required): ID of the trip that was canceled. - `reason` (enum: `no show`, `passenger not ready`, `passenger refused`, `passenger unable`, `scheduling conflict`, `appointment canceled`, `user requested`, `payer canceled`, `other`, required): Why the trip was canceled. - `driver_id` (string (uuid), required): ID of the driver the trip was on, or null if it had none. - `vehicle_id` (string (uuid), required): ID of the vehicle the trip was on, or null if it had none. ### TripUncanceledWebhookPayload Sent when a canceled trip is restored and is back in play. Treat it as a correction to an earlier `trip.canceled` and refetch the trip with `trip_id` for its current status. - `trip_id` (string (uuid), required): ID of the trip that was restored. - `driver_id` (string (uuid), required): ID of the driver on the trip, or null if it has none. - `vehicle_id` (string (uuid), required): ID of the vehicle on the trip, or null if it has none. ### TripEnRouteWebhookPayload Sent when the driver sets off toward the pickup location. Progress events are latest-wins rather than a strict sequence. Fetch the trip from the API with `trip_id` for its current details. - `trip_id` (string (uuid), required): ID of the trip the driver is en route to. - `latitude` (number (double), required): Latitude the driver's device reported, or null. - `longitude` (number (double), required): Longitude the driver's device reported, or null. - `location_accuracy` (number (double), required): Accuracy radius of that location in meters, or null. - `location_queried_at` (string (date-time), required): When the device took that location fix, or null. Older than `device_requested_at` means the position is a cached one. - `device_requested_at` (string (date-time), required): The device's own clock when the driver acted, or null when the change did not come from the app. Drives `occurred_at`. - `odometer` (number (double), required): Odometer reading the driver's device reported, or null. - `speed` (number (double), required): Speed the device reported, or null. - `heading` (number (double), required): Compass heading the device reported, or null. - `driver_id` (string (uuid), required): ID of the driver on the trip, or null if it has none. - `vehicle_id` (string (uuid), required): ID of the vehicle on the trip, or null if it has none. ### TripAtPickupWebhookPayload Sent when the driver arrives at the pickup location. Progress events are latest-wins rather than a strict sequence. Fetch the trip from the API with `trip_id` for its current details. - `trip_id` (string (uuid), required): ID of the trip whose driver reached the pickup. - `latitude` (number (double), required): Latitude the driver's device reported, or null. - `longitude` (number (double), required): Longitude the driver's device reported, or null. - `location_accuracy` (number (double), required): Accuracy radius of that location in meters, or null. - `location_queried_at` (string (date-time), required): When the device took that location fix, or null. Older than `device_requested_at` means the position is a cached one. - `device_requested_at` (string (date-time), required): The device's own clock when the driver acted, or null when the change did not come from the app. Drives `occurred_at`. - `odometer` (number (double), required): Odometer reading the driver's device reported, or null. - `speed` (number (double), required): Speed the device reported, or null. - `heading` (number (double), required): Compass heading the device reported, or null. - `driver_id` (string (uuid), required): ID of the driver on the trip, or null if it has none. - `vehicle_id` (string (uuid), required): ID of the vehicle on the trip, or null if it has none. ### TripTransportingWebhookPayload Sent when the passenger is on board and the trip is under way. Progress events are latest-wins rather than a strict sequence. Fetch the trip from the API with `trip_id` for its current details. - `trip_id` (string (uuid), required): ID of the trip now transporting its passenger. - `latitude` (number (double), required): Latitude the driver's device reported, or null. - `longitude` (number (double), required): Longitude the driver's device reported, or null. - `location_accuracy` (number (double), required): Accuracy radius of that location in meters, or null. - `location_queried_at` (string (date-time), required): When the device took that location fix, or null. Older than `device_requested_at` means the position is a cached one. - `device_requested_at` (string (date-time), required): The device's own clock when the driver acted, or null when the change did not come from the app. Drives `occurred_at`. - `odometer` (number (double), required): Odometer reading the driver's device reported, or null. - `speed` (number (double), required): Speed the device reported, or null. - `heading` (number (double), required): Compass heading the device reported, or null. - `driver_id` (string (uuid), required): ID of the driver on the trip, or null if it has none. - `vehicle_id` (string (uuid), required): ID of the vehicle on the trip, or null if it has none. ### TripAtDropoffWebhookPayload Sent when the driver arrives at the dropoff location. Progress events are latest-wins rather than a strict sequence. Fetch the trip from the API with `trip_id` for its current details. - `trip_id` (string (uuid), required): ID of the trip whose driver reached the dropoff. - `latitude` (number (double), required): Latitude the driver's device reported, or null. - `longitude` (number (double), required): Longitude the driver's device reported, or null. - `location_accuracy` (number (double), required): Accuracy radius of that location in meters, or null. - `location_queried_at` (string (date-time), required): When the device took that location fix, or null. Older than `device_requested_at` means the position is a cached one. - `device_requested_at` (string (date-time), required): The device's own clock when the driver acted, or null when the change did not come from the app. Drives `occurred_at`. - `odometer` (number (double), required): Odometer reading the driver's device reported, or null. - `speed` (number (double), required): Speed the device reported, or null. - `heading` (number (double), required): Compass heading the device reported, or null. - `driver_id` (string (uuid), required): ID of the driver on the trip, or null if it has none. - `vehicle_id` (string (uuid), required): ID of the vehicle on the trip, or null if it has none. ### TripCompletedWebhookPayload Sent when a trip reaches the completed status, either by the driver completing it or by a dispatcher marking it complete. Fetch the trip from the API with `trip_id` for its current details. - `trip_id` (string (uuid), required): ID of the trip that was completed. - `latitude` (number (double), required): Latitude the driver's device reported, or null. - `longitude` (number (double), required): Longitude the driver's device reported, or null. - `location_accuracy` (number (double), required): Accuracy radius of that location in meters, or null. - `location_queried_at` (string (date-time), required): When the device took that location fix, or null. Older than `device_requested_at` means the position is a cached one. - `device_requested_at` (string (date-time), required): The device's own clock when the driver acted, or null when the change did not come from the app. Drives `occurred_at`. - `odometer` (number (double), required): Odometer reading the driver's device reported, or null. - `speed` (number (double), required): Speed the device reported, or null. - `heading` (number (double), required): Compass heading the device reported, or null. - `driver_id` (string (uuid), required): ID of the driver on the trip, or null if it has none. - `vehicle_id` (string (uuid), required): ID of the vehicle on the trip, or null if it has none. ### TripUncompletedWebhookPayload Sent when a completed trip is reopened and is no longer complete. Treat it as a correction to an earlier `trip.completed` and refetch the trip with `trip_id` for its current status. - `trip_id` (string (uuid), required): ID of the trip that was reopened. - `driver_id` (string (uuid), required): ID of the driver on the trip, or null if it has none. - `vehicle_id` (string (uuid), required): ID of the vehicle on the trip, or null if it has none. ### TripWillCallActivatedWebhookPayload Sent when a will-call trip is activated, meaning the passenger is ready and the trip now has a real pickup time instead of a placeholder. A will-call trip is booked without one because nobody knows when the appointment will end. Activation is the moment that time is known, so `scheduled_pickup_at` is the point of this event. It moves the pickup time without sending `trip.pickup_time_changed`, which reports a rescheduling rather than an activation. - `trip_id` (string (uuid), required): ID of the trip that was activated. - `scheduled_pickup_at` (string (date-time), required): The pickup time the trip was activated for. - `driver_id` (string (uuid), required): ID of the driver on the trip, or null if it has none. - `vehicle_id` (string (uuid), required): ID of the vehicle on the trip, or null if it has none. ### TripWillCallDeactivatedWebhookPayload Sent when a will-call activation is undone and the trip goes back to waiting on the passenger. Treat it as a correction to an earlier `trip.will_call_activated`. The trip keeps a pickup time so it still holds a place in the day, and on a trip with no driver that falls back to the end of the day, so `scheduled_pickup_at` is a placeholder again rather than a time anyone confirmed. - `trip_id` (string (uuid), required): ID of the trip whose activation was undone. - `scheduled_pickup_at` (string (date-time), required): The pickup time the trip holds now that it is waiting again. - `driver_id` (string (uuid), required): ID of the driver on the trip, or null if it has none. - `vehicle_id` (string (uuid), required): ID of the vehicle on the trip, or null if it has none. ### TripPickupTimeChangedWebhookPayload Sent when a trip is rescheduled to a different pickup time. Carries both times, so a partner holding the old one can tell this apart from a redelivery without refetching. Activating or deactivating a will-call trip also moves the pickup time and sends its own event instead of this one. - `trip_id` (string (uuid), required): ID of the trip that was rescheduled. - `scheduled_pickup_at` (string (date-time), required): The new pickup time. - `previous_pickup_at` (string (date-time), required): The pickup time the trip carried before this change. - `driver_id` (string (uuid), required): ID of the driver on the trip, or null if it has none. - `vehicle_id` (string (uuid), required): ID of the vehicle on the trip, or null if it has none. ### TripPriceUpdatedWebhookPayload Sent when the price of a trip changes, whatever changed it, including a dispatcher editing it, a broker import, and the Partner API itself. This is the same amount the API returns as `price_cents`, and it carries both sides of the change so a partner holding the old one can tell this apart from a redelivery without refetching. Canceling a trip reprices it to zero or to a late-cancellation fee, and uncanceling restores it, so this can arrive alongside `trip.canceled` and `trip.uncanceled`. - `trip_id` (string (uuid), required): ID of the trip that was repriced. - `price_cents` (integer, required): The price of the trip now, in cents, or null if it carries no price. - `previous_price_cents` (integer, required): The price the trip carried before this change, in cents, or null if it carried none. ### TripAddressChangedWebhookPayload Sent when a trip is moved to a different pickup or dropoff address. `leg` names the end that moved, and one event covers one end, so a trip whose pickup and dropoff both move in a single edit sends two. The address itself is never in the payload; fetch the trip from the API with `trip_id` for it. Distance and travel time are recalculated off the new address, so a partner holding an estimate should refetch. A new unit or suite at the same street address counts, since the driver is going somewhere else. Changing the contact, the stairs, or the notes for a leg describes the same place and sends nothing. - `trip_id` (string (uuid), required): ID of the trip that was moved. - `leg` (enum: `pickup`, `dropoff`, required): Which end of the trip moved. ### PartnerTripAssignmentVehicle - `id` (string (uuid), required): The Bambi ID of the vehicle, Ex: `123e4567-e89b-12d3-a456-426614174000`. Matches `vehicle_id` on the webhook payloads and the vehicles endpoints. - `license_plate` (string, required): The license plate of the vehicle, Ex: `ABC123` - `vin` (string, required): The VIN of the vehicle, Ex: `12345678901234567` - `make` (string, required): The make of the vehicle, Ex: `Toyota` - `model` (string, required): The model of the vehicle, Ex: `Camry` - `year` (integer, required): The year of the vehicle, Ex: `2020`. Null when none is recorded - `color` (string, required): The color of the vehicle, Ex: `Red` ### PartnerTripAssignmentDriver The driver side of an assigned membership. - `id` (string (uuid), required): The Bambi ID of the driver, Ex: `123e4567-e89b-12d3-a456-426614174000`. Matches `driver_id` on the webhook payloads and the drivers endpoints. - `first_name` (string, required): The first name of the driver, Ex: `John` - `last_name` (string, required): The last name of the driver, Ex: `Doe` ### PartnerTripAssignmentAttendants - `first_name` (string, required): The first name of the attendant, Ex: `Jane` - `last_name` (string, required): The last name of the attendant, Ex: `Smith` ### PartnerTripEventActor - `first_name` (string, required): The first name of the person, Ex: `Jane` - `last_name` (string, required): The last name of the person, Ex: `Doe`