Docs

Webhooks

Set your endpoint

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

PUT /v1/webhook-endpoint
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"
    ]
  }'

Events

EventWhendata
post.scheduledScheduled or queuedpost
post.publishedLive on every networkpost
post.partialLive on some, failed on otherspost
post.failedLive nowherepost
post.cancelledCancelledpost
post.removedTaken down from a networkpost
post.rejectedRejected in review and back to draftpost
post.recycledA recycled copy was createdpost (the copy), recycledFrom
account.connectedAn account was connectedaccount
account.disconnectedDisconnected or needs reconnectingaccount
message.receivedSomeone sent a direct messageaccountId, conversationId, message
comment.receivedSomeone commented on a postaccountId, postId, comment
review.receivedA 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/…" }
      ]
    }
  }
}

Verify the signature

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"])

Retries

🚧 Not ready yet

We're finishing building it

Crier is in early access. Leave your email and you'll be among the first in, with launch terms.

or with your email

No spam. We'll only write to give you access.

You're on the list!

We'll write to you as soon as your access is ready.