API Reference
Webhooks
💬Get free consultation

Webhooks

Who can use this feature?

  • Available to all users on any plan.
  • You'll need your App ID and Secret key from Settings > API. See API overview for how to generate them.

Overview

Webhooks let Chatty notify your server in real time when something happens in a conversation — for example, when your AI assistant replies, or when a customer sends a new message. Instead of polling the API, you register a URL once and Chatty POSTs a JSON payload to it whenever a matching event fires.

Common uses:

  • Mirror conversations into your own helpdesk or database
  • Trigger an internal alert when a customer asks something the AI couldn't answer
  • Log AI replies for quality review or analytics

Events

EventFires when…
ai_responseThe AI assistant responds to a visitor.
customer_messageA customer sends a new message.

A subscription can listen to one or more of these events.


Manage subscriptions

Subscriptions are managed through a small REST API. All requests go to the Chatty webhook endpoint and must include your authentication headers (see below).

MethodPathPurpose
POST/webhook/subscriptionsCreate a subscription (upserts by URL).
GET/webhook/subscriptionsList your subscriptions.
PUT/webhook/subscriptions/:idUpdate a subscription.
DELETE/webhook/subscriptions/:idDelete a subscription.

Authentication headers

HeaderValue
X-Webhook-App-IdYour App ID (from Settings > API).
X-Webhook-SecretThe secret of one of your existing subscriptions.

Create a subscription

curl -X POST https://app.chatty.net/webhook/subscriptions \
  -H "X-Webhook-App-Id: YOUR_APP_ID" \
  -H "X-Webhook-Secret: YOUR_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/chatty-webhook",
    "events": ["ai_response", "customer_message"],
    "secret": "a-long-random-signing-secret",
    "metadata": {}
  }'
FieldRequiredDescription
urlYesWhere Chatty sends events. Must be https://.
eventsYesArray of event names to subscribe to.
secretYesYour signing secret — used to verify delivery (see below).
metadataNoAny object you want echoed back for your own bookkeeping.

Creating a subscription with a url you've already registered updates that subscription instead of creating a duplicate. To pause delivery without deleting, PUT the subscription with "isActive": false.


Delivery payloads

Chatty sends a POST with a JSON body. The shape depends on the event.

customer_message

{
  "timestamp": "2026-06-11T10:13:52.305Z",
  "shopId": "your-shop-id",
  "shopifyDomain": "your-store.myshopify.com",
  "convoId": "conversation-id",
  "message": {
    "text": "Hi, do you have the Daris Tee in size M?",
    "createdAt": "2026-06-11T10:13:52.305Z",
    "customerEmail": "[email protected]",
    "customerShopifyId": "gid://shopify/Customer/123"
  },
  "context": {
    "detectedLanguage": "en",
    "country": "US",
    "locale": "en"
  }
}

ai_response

{
  "timestamp": "2026-06-11T10:13:54.120Z",
  "shopId": "your-shop-id",
  "shopifyDomain": "your-store.myshopify.com",
  "convoId": "conversation-id",
  "query": "do you have the Daris Tee in size M?",
  "message": {
    "text": "Yes! The Daris Tee is in stock in size M.",
    "topic": "product-availability",
    "isAskBotResponse": "found",
    "chatbotProducts": [],
    "chatbotFaqs": [],
    "createdAt": "2026-06-11T10:13:54.120Z"
  }
}

For ai_response, message.isAskBotResponse is "found" when the AI had an answer and "not-found" when it didn't — a useful signal for routing unanswered questions to a human. The chatbot* arrays (chatbotProducts, chatbotFaqs, chatbotTopics, chatbotDiscounts, chatbotPages, and others) list the sources the AI used.


Verify the signature

Every delivery includes headers so you can confirm it really came from Chatty and wasn't tampered with:

HeaderDescription
X-Webhook-EventThe event name (ai_response or customer_message).
X-Webhook-TimestampUnix timestamp (seconds) of delivery.
X-Webhook-SignatureHMAC-SHA256 of the raw request body, signed with your secret.

To verify, compute the HMAC-SHA256 of the raw body using the subscription's secret and compare it to X-Webhook-Signature using a constant-time comparison.

import crypto from 'crypto'
 
function verify(rawBody, signatureHeader, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex')
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signatureHeader)
  )
}
!

Always verify the signature against the raw, unparsed request body. If your framework parses JSON before you can read the raw bytes, the re-serialized body may not match the signature.


Delivery behavior

  • Respond fast. Chatty waits up to 10 seconds for your endpoint to respond, then aborts the request.
  • No automatic retries. If your endpoint is down or slow, that delivery is dropped. Make your handler resilient — acknowledge quickly (return 2xx) and process asynchronously.
  • Independent delivery. Events are delivered to each subscription independently; one failing endpoint doesn't affect others.

Requirements & limits

  • url must use https:// (for local development, http://localhost and http://127.0.0.1 are allowed).
  • Each subscription has its own secret, separate from your API Secret key.

FAQs

Can I have more than one webhook URL?

Yes. Create a separate subscription for each URL. Each one can listen to a different set of events and uses its own signing secret.

How do I temporarily stop receiving events?

PUT /webhook/subscriptions/:id with {"isActive": false}. Set it back to true to resume — you don't need to recreate the subscription.

What happens if my server is down?

The event for that window is dropped — there's no retry queue. Keep your endpoint highly available, return 2xx immediately, and do the heavy work in the background.


Need help?

If your endpoint isn't receiving events, double-check the url is publicly reachable over HTTPS and returns 2xx within 10 seconds. Still stuck? Contact the Chatty support team from your dashboard.