Webhooks
Webhooks Overview
Webhooks are how FrontRow notifies your application when something happens in a creator’s account — a message, a new subscriber, a tip. Instead of polling the API, you register an endpoint and FrontRow POSTs an event payload to it within milliseconds of the trigger.
Available events
FrontRow currently supports 6 event types. Each has its own payload schema documented on its dedicated page.
- A fan sent you a direct message.
message.received - A fan opened a message you sent and marked it read.
message.read - A user followed your profile.
follower.new - A new paid subscription started.
subscriber.new - A fan purchased a PPV post or message.
purchase.received - A fan sent you a tip.
tip.received
Registering an endpoint
From your creator dashboard, open Settings → Developer → Webhooks and add an endpoint URL. Pick which events should trigger deliveries. FrontRow returns a unique signing secret per endpoint — copy it immediately, it’s only shown once.
Endpoints must be publicly reachable HTTPS URLs. Plain HTTP and loopback addresses are rejected at registration time. For local development, tunnel a public URL to your machine with ngrok or cloudflared.
Payload format
Every delivery is a JSON POST with three top-level fields: event, data, and timestamp. The shape of data depends on the event — see each event’s page for its schema.
| 1 | { |
| 2 | "event": "message.received", |
| 3 | "data": { /* event-specific payload */ }, |
| 4 | "timestamp": "2026-04-28T12:10:01Z" |
| 5 | } |
Headers
X-FrontRow-Event— the event name (e.g.message.received).X-FrontRow-Delivery— a unique delivery ID. Use it for idempotency — the same delivery may be retried.X-FrontRow-Signature— an HMAC-SHA256 signature over the raw request body, prefixed withsha256=.X-FrontRow-Timestamp— the ISO 8601 timestamp the event was generated. Reject deliveries older than five minutes to mitigate replay attacks.
Signature verification
Compute the HMAC of the raw body using your endpoint’s signing secret, then compare against X-FrontRow-Signature with a timing-safe equality check. Reject any request that fails.
| 1 | import crypto from "node:crypto"; |
| 2 | |
| 3 | export function verify( |
| 4 | rawBody: Buffer, |
| 5 | header: string | undefined, |
| 6 | secret: string |
| 7 | ): boolean { |
| 8 | if (!header) return false; |
| 9 | |
| 10 | const expected = |
| 11 | "sha256=" + |
| 12 | crypto.createHmac("sha256", secret).update(rawBody).digest("hex"); |
| 13 | |
| 14 | const a = Buffer.from(header); |
| 15 | const b = Buffer.from(expected); |
| 16 | |
| 17 | return a.length === b.length && crypto.timingSafeEqual(a, b); |
| 18 | } |
Delivery, retries, and idempotency
- Acknowledge fast. Return a 2xx within 5 seconds. Acknowledge first, then process in a background queue.
- Retries. Non-2xx responses (or timeouts) trigger exponential backoff retries up to 24 hours. After the final attempt, the delivery is dropped and visible in the dashboard’s delivery log.
- Idempotency. Use
X-FrontRow-Deliveryas a primary key in your handler so retries don’t double-process. - Ordering. Webhooks are not strictly ordered. If you need a canonical order, sort by
timestampafter dedup.
Testing
From the webhook dashboard, click Send test to deliver a sample payload for any event type. You can also trigger one programmatically:
| 1 | curl https://frontrow.center/api/v1/webhooks/test \ |
| 2 | -H "Authorization: Bearer $FRONTROW_API_KEY" \ |
| 3 | -H "Content-Type: application/json" \ |
| 4 | -d '{ "webhookId": "wh_abc123", "event": "message.received" }' |
Next steps
Pick an event from the sidebar to see its payload, or jump straight into building a handler with the chatbot tutorial.