Open API v1
Receive and verify webhooks
TaggoAI POSTs a signed JSON event to each endpoint you register.
Required scope: webhooks:manage.
Create an endpoint
The URL must be HTTPS. The signing secret is returned once.
bash
curl -X POST https://api.taggoai.com/open/v1/webhook-endpoints \
-H "Authorization: Bearer tg_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/taggo/webhooks",
"events": ["contact.created", "ticket.created", "message.received"]
}'
Store secret (whsec_...). List responses omit it.
Event catalog
| Event | When |
|---|---|
contact.created | A contact is created |
contact.updated | A contact is updated |
ticket.created | A ticket is created |
ticket.updated | A ticket is updated |
message.received | A customer message arrives |
conversation.assigned | Assignees on a conversation change |
Payload
json
{
"id": "evt_...",
"object": "event",
"type": "contact.created",
"created": 1710000000,
"data": { "id": "...", "object": "contact" }
}
Headers:
http
Taggo-Signature: t=1710000000,v1=hex_hmac
Taggo-Event: contact.created
Taggo-Delivery: evt_...
Delivery retries up to 4 times with backoff. After 15 consecutive failures the endpoint is disabled.
Verify the signature
Compute HMAC-SHA256 of {timestamp}.{raw_body} using the endpoint secret. Compare it to v1. Reject if the timestamp is older than 5 minutes.
Node.js
js
import crypto from 'crypto';
function verify(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(
header.split(',').map((item) => item.split('='))
);
const timestamp = Number(parts.t);
if (Math.abs(Date.now() / 1000 - timestamp) > toleranceSec) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`)
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}
Python
python
import hmac, hashlib, time
def verify(raw_body: bytes, header: str, secret: str, tolerance=300) -> bool:
parts = dict(item.split("=", 1) for item in header.split(","))
timestamp = int(parts["t"])
if abs(time.time() - timestamp) > tolerance:
return False
expected = hmac.new(
secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(parts["v1"], expected)
PHP
php
function verify(string $rawBody, string $header, string $secret, int $tolerance = 300): bool {
$parts = [];
foreach (explode(',', $header) as $item) {
[$k, $v] = explode('=', $item, 2);
$parts[$k] = $v;
}
$timestamp = (int) $parts['t'];
if (abs(time() - $timestamp) > $tolerance) return false;
$expected = hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret);
return hash_equals($expected, $parts['v1']);
}