Webhooks
Webhooks on Yarla are HTTP requests we send to your server at a fixed moment in the conversation. You create them as an HTTP request action; this article covers what all three moments have in common: the signature, the retry policy and the timeouts.
Three moments
| Moment | What happens | Article |
|---|---|---|
| Before the call | As soon as an inbound phone call arrives, before the greeting, we send the caller's number, your own number and your business details to your endpoint. This does not happen on outbound calls, SMS, WhatsApp or webchat. The assistant receives the JSON you return as context; you use the values in the greeting as {{key}} and in after-conversation actions as {{inboundContext.key}}. | Inbound webhook (pre-call) |
| During the conversation | Based on your condition, the assistant decides to call your endpoint (a "tool call"), for example to look up an order status. Your response goes back to the assistant, which uses it in the conversation. | Webhook during the call |
| After the conversation | Once the conversation has ended and the summary and custom variables have been extracted, we send the conversation data to your endpoint. | Webhook after the call |
Want a message for every ended conversation, new request and appointment across your whole account, without an action per assistant? Use Event webhooks (Enterprise). They are signed the same way.
All three are POST requests with Content-Type: application/json by default. In the action you can change the method, headers and body. The signature is always included, except on GET: that request has no body and no signature.
Verify the signature
Every request we send, except GET, carries the header:
X-Yarla-Signature: t=1757581245,v1=5f1c9b2a7d0e4c6b8a1f3e5d7c9b2a4f6e8d0c2b4a6f8e0d2c4b6a8f0e2d4c6btis the Unix time in seconds at which we sent the request.v1isHMAC-SHA256(secret, t + "." + rawBody), hex encoded.
You find the secret under Settings → Connections as Webhook secret. Generate new creates a new secret after you confirm; the old one stops working, so update your server straight after. Only admins of your own business see and renew the secret here. A reseller or support agent viewing your account does not see it.
Verify like this:
- Split the header on the comma and read
tandv1. - Reject the request if the difference between now and
tis more than 300 seconds (replay protection). - Compute the HMAC over exactly the raw body, meaning the bytes as received, not re-serialised JSON.
- Compare the result with
v1using a constant-time comparison.
Example in Node.js with Express, for an after-conversation action:
const express = require('express');
const crypto = require('crypto');
const app = express();
const SECRET = process.env.YARLA_WEBHOOK_SECRET;
const TOLERANCE_SECONDS = 300;
function verifySignature(header, rawBody) {
if (!header) return false;
const parts = Object.fromEntries(header.split(',').map((kv) => kv.split('=')));
const t = Number(parts.t);
const v1 = parts.v1;
if (!t || !v1) return false;
if (Math.abs(Date.now() / 1000 - t) > TOLERANCE_SECONDS) return false;
const expected = crypto
.createHmac('sha256', SECRET)
.update(`${t}.`)
.update(rawBody) // Buffer with the raw bytes
.digest('hex');
const a = Buffer.from(expected, 'hex');
const b = Buffer.from(v1, 'hex');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
// express.raw keeps req.body as a Buffer instead of parsed JSON
app.post('/yarla/webhook', express.raw({ type: 'application/json' }), (req, res) => {
if (!verifySignature(req.get('X-Yarla-Signature'), req.body)) {
return res.status(401).send('invalid signature');
}
const event = JSON.parse(req.body.toString('utf8'));
// Answer immediately, then process asynchronously
res.status(200).json({});
setImmediate(() => handleEvent(event));
});
function handleEvent(event) {
// Without a custom body the request contains conversationId, summary and outcome, among others
if (event.outcome === 'callback_requested') {
// for example: create a task in your CRM
}
}
app.listen(3000);Use the raw body
If your framework parses the JSON before you verify the signature, you compute the HMAC over a different string and it will never match. In Express use express.raw; other frameworks have an equivalent option to access the original bytes.
Retry policy
We do not retry a failed request automatically, and you cannot re-run it manually either. A request counts as failed on a status code outside 2xx, on a timeout or when your endpoint cannot be reached. We follow redirects and the last response counts. Use the final address in the action: a redirect with 301, 302 or 303 turns your request into a GET without a body.
- After the conversation: the result is shown on the conversation in the Inbox. Open Technical details and look under What the actions did: it shows the status code and, on an error status, the start of the response. On a timeout or an unreachable endpoint it shows only the error message. If an action fails, the next actions still run.
- Before the call: the assistant starts without the details from that action. What your endpoint did return is under Technical details, in Details looked up before the call; a failed request does not show there.
- During the conversation: the result is not shown on the conversation. On an error status the assistant hears that the lookup failed and deals with it in the conversation.
Design your endpoint for after-conversation actions accordingly: verify the signature, store the request, answer 2xx immediately and process the data asynchronously. If you process inside the request itself, you hit the timeout as soon as your CRM is a little slow. For actions before the call and during the conversation the assistant needs your answer: return the data straight away, within the timeout below.
IP allowlisting
A list of fixed IP addresses is not available: our egress addresses can change. Secure your endpoint with HTTPS and the signature. For an extra layer, add a custom header with a long random token in the action and check it on your server. On a GET request such a header is the only check, because no signature is sent.
Timeouts
| Moment | Timeout | When exceeded |
|---|---|---|
| Before the call | 3 seconds | The assistant starts without the details from this action. |
| During the conversation | 6 seconds | The lookup fails and the assistant gets no data from your endpoint. On a phone call the assistant can go quiet, so answer well within this time. |
| After the conversation | 8 seconds | The action is marked as failed on the conversation. |
If you regularly get close to these limits, see Troubleshooting: webhooks.