Skip to content

Webhooks

One HTTPS URL per workspace. Without events you get all of them. The signing secret is only returned when it is created: keep it.

Ventana de terminal
curl -X PUT "https://api.usecrier.com/v1/webhook-endpoint" \
-H "Authorization: Bearer $CRIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://app.acme.com/webhooks/crier",
"events": [
"post.published",
"post.failed",
"account.disconnected"
]
}'
Event When data
post.scheduled Scheduled or queued post
post.published Live on every network post
post.partial Live on some, failed on others post
post.failed Live nowhere post
post.cancelled Cancelled post
post.removed Taken down from a network post
post.rejected Rejected in review and back to draft post
post.recycled A recycled copy was created post (the copy), recycledFrom
account.connected An account was connected account
account.disconnected Disconnected or needs reconnecting account
message.received (soon) Someone sent a direct message accountId, conversationId, message
comment.received Someone commented on a post accountId, postId, comment
review.received (soon) A new review arrived (Google Business) accountId, review
Body
{
"id": "evt_9a8s7d",
"type": "post.published",
"createdAt": "2026-10-23T10:00:05.000Z",
"data": {
"post": {
"id": "pst_7q1w0e",
"status": "published",
"targets": [
{ "accountId": "acc_3k9x2m", "platform": "instagram", "status": "published", "url": "https://www.instagram.com/p/…" }
]
}
}
}

Each delivery carries Crier-Event, Crier-Event-Id and Crier-Signature: t=<seconds>,v1=<hex>. v1 is the HMAC-SHA256 of <t>.<body> with your secret. Compare it against the unparsed body and reject signatures older than 5 minutes.

Node
import { createHmac, timingSafeEqual } from 'node:crypto';
export const verifyCrierSignature = (rawBody, header, secret) => {
const { t, v1 } = Object.fromEntries(header.split(',').map((part) => part.split('=')));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
};
Python
import hmac, hashlib, time
def verify_crier_signature(raw_body: bytes, header: str, secret: str) -> bool:
parts = dict(part.split("=", 1) for part in header.split(","))
if abs(time.time() - int(parts["t"])) > 300:
return False
expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"])
  • Answer with a 2xx within 10 seconds. Do the heavy work afterwards.
  • If you fail, we retry several times with growing waits.
  • The same event may arrive more than once: use Crier-Event-Id to process it only once.

© 2026 Crier by TWOFACES ·usecrier.com ·Dashboard ·soporte@twofacesco.com