An incoming webhook lets an external system start a flow. Your shop system, customer data platform or middleware sends charles an event, and charles runs the flow for that contact.
Use this when charles has no native integration with the system holding your data. If you use Shopify, abandoned carts and orders already reach charles automatically: see Abandoned cart flow (Shopify).
What you can build
Use case | What starts the flow |
Abandoned cart | A shopper adds to cart and does not buy |
Back-in-stock | An item a shopper asked about returns to stock |
Price drop | A watched item falls below a set price |
Re-activation | A customer has not bought for a set period |
Loyalty and tier changes | A customer reaches a new tier, or points are expiring |
Booking reminders | A reservation is coming up |
Before you begin
Contacts are opted in to WhatsApp.
charles only messages contacts with an opt-in. Events for anyone else are accepted, but nothing sends.
-> See Create a welcome flow / opt-in flow.
Phone numbers are in international format.
Include the country code, with no spaces or dashes: +491701234567. charles uses the phone number to match an event to a contact, so events without one cannot be delivered.
-> To sync contacts on a schedule, see the Contact API.
Your product catalogue is imported, if you want product detail in messages.
Events often carry a product ID and nothing else. With your catalogue in charles you can look up the name, image, price and link from that ID inside the flow. Otherwise, include the full product detail in the event itself.
-> To import on a schedule, see sFTP integration. Products also sync automatically from a connected shop system such a shopify.
Like a start button, the Incoming webhook trigger starts the flow whenever a specific event or action occurs in an external system.
Set up the trigger
Create a new flow.
Under trigger types, select Incoming webhook. If there is no Incoming webhook under your trigger types, please contact our Customer Support team so they can enable it for you.
3. Copy the Webhook URL and API Key. You will paste them into the system that sends the event.
4. In payload body, enter the fields your event will contain. These become the variables available in your flow, so any field you leave out cannot be used in a message.
The payload sent from the external system's webhook must match the payload configured in the incoming webhook in charles.
5. Continue building the flow.
Important: After any webhook trigger there should always
be set up the Send Update Node (marketing template), because you open the conversation with a user.
Send the event
Your system sends a POST request to the webhook URL. You choose the field names, and charles stores the event as you send it.
{
"phone": "+49XXXXXXXXXX",
"event_type": "abandoned_cart",
"first_name": "Alex",
"cart_id": "C-88213",
"cart_url": "https://yourshop.com/cart/recover/88213",
"cart_value": 149.90,
"currency": "EUR",
"products": [
{
"product_id": "SKU-4433221",
"name": "Merino Crew Knit",
"url": "https://yourshop.com/p/merino-crew-knit",
"image_url": "https://yourshop.com/img/merino-crew.jpg",
"price": 149.90,
"quantity": 1
}
]
}phoneis required. Every other field is optional and exists for personalisation.Inside
products, sendproduct_idalone if your catalogue is imported, or includename,urlandimage_urlto use them directly.Event names cannot contain spaces. Use
abandoned_cart, notabandoned cart.Field names must match what you entered in the payload body, and must stay the same once a flow is live. Renaming a field breaks any flow using it.
Plan for up to 10,000 requests per 15 minutes. Contact support if you expect more, or if you want to send a batch of historic events.
Use event data in your messages
Message & Update nodes
Top-level fields. In message and update nodes, select Add variable </> and choose the field.
Condition node
Use the variable data in the condition node by selecting the ‘Flow variable’ event:
Important:
Lists and nested fields. The variable picker cannot reach inside a list, so a cart holding several products needs the Define Variable node. Use it to extract what you need, then reference that variable in your message.
{{REST_TRIGGER.event_data.Product_Name}}Product lookups by ID. With your catalogue imported, the get_product filter returns a product from its SKU:
{{ '123233' | get_product: 'id' }}
{{REST_TRIGGER.products[0].name }}Replace '123233' with the variable holding your product ID. This also works while iterating over a list of products.
For examples, including listing every product in a cart and finding the most expensive item, see Set up WhatsApp flows for product-based automations.
Test your flow
Send a test event to the webhook URL using your own phone number.
Confirm the flow triggered and the message arrived.
Check that every variable resolved. Blank spaces or raw field names mean a field name in your event does not match the payload body.
Send a small number of real events before turning the flow on for everyone.
Troubleshooting
What you see | Cause |
The flow never triggers | The phone number is missing or not in international format |
The flow triggers but variables are empty | A field name in the event does not match the payload body |
Product names or images are missing | Your event sends only product IDs and your catalogue is not imported. The image URL returns an incorrect format of the picture. |
An image does not display | WhatsApp does not accept the format. Use a JPEG or PNG on a publicly reachable URL |
Only some contacts receive the message | The others are not opted in, or reached charles without a phone number |
The event is rejected | A required field is missing or has the wrong type, or the payload is wrong. |
If the problem persists, contact Customer Support with the flow name or a link to it and an example of the event you sent.
API docs for the incoming webhook API
Refer to this document for detailed documentation on how to trigger a flow
Related articles





