Webhooks
Texa API webhooks
Signed events for every conversation, reply, action, handover and call, retried for about a day.
Texa POSTs each event to your server as it happens. Add an endpoint in Texa Desk under Texa AI → Developers → Webhooks: its URL, live or sandbox events, and every event type or the ones you pick. You get a signing secret, shown once.
- Live endpoints must be
httpsand reachable from the internet. Sandbox endpoints may usehttpwhile you build (through a tunnel such as ngrok: private addresses are never called). - Send a test event in Texa Desk posts a
pingat once and shows the answer.
What arrives
POST https://your-server/texa/webhooks
Content-Type: application/json
X-Texa-Timestamp: 1790000000
X-Texa-Signature: sha256=5d41402abc4b2a76b9719d911017c592...
X-Texa-Event-Id: evt_431
X-Texa-Event-Type: conversation.reply
X-Texa-Delivery-Id: whd_12
{"id": "evt_431", "type": "conversation.reply", "created_at": "2026-09-27T10:00:03Z",
"environment": "live", "conversation_id": "cnv_8a7f0c...",
"data": {"type": "reply", "reply_id": "rpl_...", "format": "chat", "text": "..."}}
The body is the same event as on GET /v1/events, plus environment.
Check it came from Texa
Compute the signature over the raw body, before any JSON parsing, and compare in constant time. Reject a timestamp more than 5 minutes old.
import hashlib, hmac, time
def verify(secret: str, headers, raw_body: bytes) -> bool:
ts = headers["X-Texa-Timestamp"]
if abs(time.time() - int(ts)) > 300:
return False
expected = "sha256=" + hmac.new(secret.encode(), ts.encode() + b"." + raw_body,
hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, headers["X-Texa-Signature"])
import crypto from 'node:crypto';
export function verify(secret, headers, rawBody) {
const ts = headers['x-texa-timestamp'];
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
const expected = 'sha256=' + crypto.createHmac('sha256', secret)
.update(`${ts}.`).update(rawBody).digest('hex');
const given = headers['x-texa-signature'] || '';
return given.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected));
}
The same signature scheme is used on every request Texa sends you: action webhooks and monitor alerts too.
Answer fast, handle once
- Answer any 2xx within 10 seconds, then do the work. Anything else, or no answer, is tried again after 1 minute, 5 minutes, 30 minutes, then 2, 5, 10 and 10 hours: 8 attempts over about a day. After that the delivery is marked failed, and you can send it again from Texa Desk.
- Delivery is at least once: use
X-Texa-Event-Id(or the body'sid) to ignore a repeat. - Order is not guaranteed across retries. Use
created_at, or the feed, when order matters. - An endpoint whose every delivery has failed for 5 days is switched off, and Texa Desk says so. Switch it on again once it is fixed.
- Each delivery's attempts (time, status, error) are in Texa Desk, for 30 days.
The feed, GET /v1/events?after=<cursor>, is the complete record. If your server was
down, read the feed from your last cursor instead of waiting for retries.
Event types
| Type | When |
|---|---|
conversation.opened |
a conversation was opened |
conversation.reply |
Texa AI replied, including replies that came after your request returned |
conversation.action_request |
Texa AI asked for an action (codes the customer typed are masked here) |
conversation.handover |
Texa AI handed the conversation to people |
conversation.handback |
people handed it back to Texa AI |
conversation.closed |
it was closed; resolved says whether Texa AI resolved it |
conversation.human_message |
a person answered from Texa Desk: show text in your app (handing over) |
call.started, call.ended |
a phone or in-app call started or ended |
media.understood, media.failed |
a voice note, photo, document or video was understood, or could not be |
quality.scored |
a closed conversation was scored |
monitor.finding |
one of your monitors found something |
interview.completed |
a research interview was completed |
report.ready |
a report is ready |
survey.response |
a customer completed a survey |
ping |
a test event you sent from Texa Desk |
New types may be added. Ignore types you do not know, and subscribe to types by name if you want only those.