Withlocals Webhooks API

Out-of-band events delivered by Withlocals to a partner-registered URL. Register at `PUT /webhooks`. See the *Webhooks* section for the delivery contract and the events Withlocals sends.

Operations 3

GET /webhooks Get current webhook registration #
PUT /webhooks Register or update the webhook URL #
DELETE /webhooks Remove the webhook registration #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/withlocals:withlocals-webhooks-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

withlocals-webhooks-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Withlocals Partner Webhooks API
  version: 1.0.0
  description: 'A single contract for OTA partners and other commercial integrations.

    Covers products, availability, and the create -> amend -> cancel booking

    lifecycle.


    `POST /bookings` creates a `CONFIRMED` booking.'
  contact:
    name: Withlocals Partner Integrations
    email: partners@withlocals.com
  x-logo:
    url: ./assets/logo.svg
    altText: Withlocals
    href: https://www.withlocals.com
    backgroundColor: '#ffffff'
servers:
- url: https://test-api.withlocals.com/v1/partner
  description: Test / Sandbox
security:
- bearerAuth: []
tags:
- name: Webhooks
  description: 'Out-of-band events delivered by Withlocals to a partner-registered URL.

    Register at `PUT /webhooks`. See the *Webhooks* section for the delivery

    contract and the events Withlocals sends.'
paths:
  /webhooks:
    get:
      tags:
      - Webhooks
      operationId: getWebhook
      summary: Get current webhook registration
      description: 'Returns the partner''s currently registered webhook URL. The signing

        `secret` is **not** returned — it is only revealed once, on first

        registration.


        Possible errors: `NOT_FOUND` (no webhook registered), `UNAUTHORIZED`.'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Webhook'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    put:
      tags:
      - Webhooks
      operationId: setWebhook
      summary: Register or update the webhook URL
      description: 'Registers a webhook URL on first call (`201`), or updates an existing

        registration (`200`).


        On first registration, the response includes a `secret` — save it.

        Withlocals will not return it again. Subsequent reads and updates omit

        the secret. To rotate, `DELETE /webhooks` and re-register.


        The URL must be HTTPS and reachable from the public internet.


        Possible errors: `BAD_REQUEST` (URL invalid or not HTTPS), `UNAUTHORIZED`.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookRegistration'
      responses:
        '200':
          description: Updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Webhook'
        '201':
          description: Registered (first time — `secret` included in response)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Webhook'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
    delete:
      tags:
      - Webhooks
      operationId: deleteWebhook
      summary: Remove the webhook registration
      description: 'Unregisters the partner''s webhook. No further events will be delivered

        until a new URL is registered via `PUT /webhooks`.


        Possible errors: `NOT_FOUND` (nothing registered), `UNAUTHORIZED`.'
      responses:
        '204':
          description: Removed
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
webhooks:
  bookingCancelled:
    post:
      tags:
      - Webhooks
      operationId: bookingCancelledWebhook
      summary: Booking cancelled
      description: 'Sent to the partner''s registered webhook URL when a booking transitions

        to `CANCELLED`, regardless of who initiated the cancellation (guest,

        host, admin, or system no-show).


        **Delivery semantics:**


        - HTTP `POST` with `Content-Type: application/json`.

        - **At-least-once.** Retries on non-2xx for ~24h with exponential

        backoff. Partners MUST dedupe on `eventId`.

        - **Acknowledge fast.** Any 2xx response stops retries. Process the

        event asynchronously if work is slow — Withlocals retries after 10s.


        **Signature verification:**


        Every delivery includes an `X-Withlocals-Signature` header of the form

        `t={unix-seconds},v1={hex-hmac}`. Compute

        `HMAC-SHA256(secret, "{t}.{raw-body}")` and constant-time-compare to

        `v1`. Reject if the timestamp is older than 5 minutes (replay window).'
      security: []
      parameters:
      - name: X-Withlocals-Signature
        in: header
        required: true
        description: 'HMAC-SHA256 signature with timestamp.

          Format: `t={unix-seconds},v1={hex-digest}`.

          '
        schema:
          type: string
        example: t=1750000000,v1=5257a869e7ecebeda32affa62cdca3fa...
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BookingCancelledEvent'
      responses:
        2XX:
          description: Acknowledged — Withlocals stops retrying.
components:
  responses:
    Unauthorized:
      description: Missing or invalid Bearer token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: UNAUTHORIZED
            errorMessage: Missing or invalid API token
            requestId: req_7c2b18d1
    BadRequest:
      description: The request is malformed or fails validation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: BAD_REQUEST
            errorMessage: '`date` is required.'
            requestId: req_7c2b18d2
    NotFound:
      description: The resource does not exist or is not visible to this partner.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: NOT_FOUND
            errorMessage: No product with that id.
            requestId: req_7c2b18d3
  schemas:
    Error:
      type: object
      description: 'Error envelope.

        '
      required:
      - error
      - errorMessage
      properties:
        error:
          type: string
          description: Stable error code. Partners are expected to switch on this value.
          enum:
          - BAD_REQUEST
          - UNAUTHORIZED
          - FORBIDDEN
          - NOT_FOUND
          - CONFLICT
          - PRECONDITION_FAILED
          - INTERNAL_ERROR
        errorMessage:
          type: string
          description: Human-readable message. Not stable; do not parse.
          example: Hold expired before confirmation.
        requestId:
          type: string
          description: Trace id for support requests.
          example: req_5f3a9b71
    WebhookRegistration:
      type: object
      description: 'Request body for `PUT /webhooks`. Only `url` is accepted — the signing

        `secret` is generated by Withlocals and returned (once) in the `201`

        response, never supplied by the partner.

        '
      required:
      - url
      properties:
        url:
          type: string
          format: uri
          description: HTTPS URL where webhook events are POSTed.
          example: https://partner.example.com/withlocals/webhook
    BookingCancelledEvent:
      type: object
      description: 'Payload of the `booking.cancelled` webhook. Thin by design — partner

        refetches the full booking via `GET /bookings/{bookingId}` if needed.


        `status` and `cancellationReason` mirror the booking API: `status` is the

        lifecycle state (always `CANCELLED` for this event) and `cancellationReason`

        identifies who initiated the cancellation.

        '
      required:
      - eventId
      - eventType
      - occurredAt
      - bookingId
      - status
      - cancellationReason
      properties:
        eventId:
          type: string
          format: uuid
          description: 'Unique per delivery. Partners SHOULD dedupe on this to tolerate

            at-least-once delivery.

            '
          example: 9c3b5d8e-1f4a-4c2b-8d6e-7f0a1b2c3d4e
        eventType:
          type: string
          enum:
          - booking.cancelled
          example: booking.cancelled
        occurredAt:
          type: string
          format: date-time
          description: When the cancellation happened.
          example: '2026-06-15T09:42:11Z'
        bookingId:
          type: string
          format: uuid
          description: Withlocals booking id. Refetch via `GET /bookings/{bookingId}` for full state.
          example: 7c9e6679-7425-40de-944b-e07fc1f90ae7
        status:
          type: string
          enum:
          - CANCELLED
          description: Booking lifecycle state. Always `CANCELLED` for this event.
          example: CANCELLED
        cancellationReason:
          type: string
          enum:
          - CANCELLEDBYGUEST
          - CANCELLEDBYHOST
          - CANCELLEDBYADMIN
          - HOSTNOSHOW
          description: 'Present when `status=CANCELLED`. Partner-initiated cancellations

            (`DELETE /bookings/{bookingId}`) always set `CANCELLEDBYGUEST`; the

            other values appear on bookings cancelled internally by the host,

            admin, or marked as a no-show.

            '
    Webhook:
      type: object
      description: 'Webhook registration. A single URL receives all event types; partners

        dispatch by the `eventType` field in each delivered payload.


        The `secret` is returned **only on first registration** (the `201` response

        of `PUT /webhooks`). Subsequent reads and updates exclude it — save it on

        receipt. To rotate, `DELETE /webhooks` then `PUT /webhooks` again.

        '
      required:
      - url
      properties:
        url:
          type: string
          format: uri
          description: HTTPS URL where webhook events are POSTed.
          example: https://partner.example.com/withlocals/webhook
        secret:
          type: string
          description: 'HMAC-SHA256 signing secret. Used to verify `X-Withlocals-Signature` on

            delivered events. Returned only on first registration.

            '
          example: whsec_a1b2c3d4e5f6a7b8c9d0e1f2
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: opaque
      description: "Per-partner opaque API token issued by Withlocals. Send on every\nrequest as:\n\n    Authorization: Bearer <token>\n"