> ## Documentation Index
> Fetch the complete documentation index at: https://gowa-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Chatwoot webhook endpoint

> Receives webhook events from Chatwoot and sends messages to WhatsApp.
Configure this URL in your Chatwoot inbox webhook settings.

When CHATWOOT_WEBHOOK_SECRET is set the request must prove knowledge of
it. Recommended: Chatwoot's own signature, sent by Chatwoot when the API
channel has a webhook secret — `X-Chatwoot-Timestamp` (unix seconds) and
`X-Chatwoot-Signature: sha256=<hex HMAC-SHA256 of "<timestamp>.<raw body>">`.
The timestamp must be within CHATWOOT_WEBHOOK_SIGNATURE_TOLERANCE (5m by
default) of the server clock. Also accepted: `X-Hub-Signature-256`
(HMAC-SHA256 of the raw body), the secret in `X-Chatwoot-Webhook-Secret`
or `X-Gowa-Chatwoot-Secret`, or the `secret` query parameter (discouraged:
the secret then appears in URLs and logs).

The secret that applies is the secret of the device the payload is
routed to: that device config's `webhook_secret` when it has one (the
global secret is then not accepted for it), CHATWOOT_WEBHOOK_SECRET
otherwise and when no device resolves. A Chatwoot-signed request that
was already accepted (answered 2xx) inside the tolerance window is
acknowledged with 200 and not acted on again. One that was answered
with any other status is not remembered, so sending the identical
request again is handled.




## OpenAPI

````yaml /openapi.yml post /chatwoot/webhook
openapi: 3.0.0
info:
  title: WhatsApp API MultiDevice
  version: 9.7.0
  description: |
    This API is used for sending whatsapp via API.

    The web dashboard is a separate project (gowa-ui); the server downloads its
    latest release asset and serves it at `/` (or returns a JSON banner when
    APP_UI_ENABLED=false).

    Device scoping:
    - Send `X-Device-Id` on all device-scoped REST calls.
    - WebSocket: connect to `/ws?device_id=<id>`.
    - WebSocket auth (when basic auth is enabled): browsers cannot set an
      Authorization header on WebSocket connections, so also pass
      `&authorization=<base64(user:pass)>` in the query string. Use TLS in
      production since the credential is visible in the URL.
servers:
  - url: http://localhost:3000
security:
  - basicAuth: []
tags:
  - name: app
    description: Initial Connection to Whatsapp server
  - name: device
    description: Device management for multi-device support
  - name: user
    description: Getting information
  - name: send
    description: Send Message (Text/Image/File/Video).
  - name: message
    description: Message manipulation (revoke/react/update).
  - name: call
    description: Call management (reject incoming calls)
  - name: chat
    description: Chat conversations and messaging
  - name: group
    description: Group setting
  - name: newsletter
    description: newsletter setting
  - name: chatwoot
    description: Chatwoot integration for customer support
paths:
  /chatwoot/webhook:
    post:
      tags:
        - chatwoot
      summary: Chatwoot webhook endpoint
      description: >
        Receives webhook events from Chatwoot and sends messages to WhatsApp.

        Configure this URL in your Chatwoot inbox webhook settings.


        When CHATWOOT_WEBHOOK_SECRET is set the request must prove knowledge of

        it. Recommended: Chatwoot's own signature, sent by Chatwoot when the API

        channel has a webhook secret — `X-Chatwoot-Timestamp` (unix seconds) and

        `X-Chatwoot-Signature: sha256=<hex HMAC-SHA256 of "<timestamp>.<raw
        body>">`.

        The timestamp must be within CHATWOOT_WEBHOOK_SIGNATURE_TOLERANCE (5m by

        default) of the server clock. Also accepted: `X-Hub-Signature-256`

        (HMAC-SHA256 of the raw body), the secret in `X-Chatwoot-Webhook-Secret`

        or `X-Gowa-Chatwoot-Secret`, or the `secret` query parameter
        (discouraged:

        the secret then appears in URLs and logs).


        The secret that applies is the secret of the device the payload is

        routed to: that device config's `webhook_secret` when it has one (the

        global secret is then not accepted for it), CHATWOOT_WEBHOOK_SECRET

        otherwise and when no device resolves. A Chatwoot-signed request that

        was already accepted (answered 2xx) inside the tolerance window is

        acknowledged with 200 and not acted on again. One that was answered

        with any other status is not remembered, so sending the identical

        request again is handled.
      operationId: chatwootWebhook
      parameters:
        - name: X-Chatwoot-Signature
          in: header
          description: >-
            Chatwoot signature: sha256=<hex HMAC-SHA256 of "<timestamp>.<raw
            body>" keyed with the webhook secret>
          schema:
            type: string
        - name: X-Chatwoot-Timestamp
          in: header
          description: Unix time (seconds) the webhook was signed at
          schema:
            type: string
        - name: secret
          in: query
          description: The webhook secret. Discouraged; prefer the signature headers.
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              description: Chatwoot webhook payload (see Chatwoot documentation)
      responses:
        '200':
          description: Webhook processed
        '401':
          description: >-
            Secret or signature missing or invalid for the device the request is
            routed to, or the signature timestamp is outside the tolerance
            window
        '503':
          description: >-
            Device not available, the routed device's config could not be read,
            or an identical signed request is still being handled
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBadRequest'
components:
  schemas:
    ErrorBadRequest:
      type: object
      properties:
        code:
          type: string
          example: 400
          description: HTTP Status Code
        message:
          type: string
          example: field cannot be blank
          description: Detail error message
        results:
          type: object
          example: null
          description: additional data
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.