Docs
Backend events API
Send signups, purchases, errors and deploys from your own backend. They roll up into daily metrics and show up as markers on your change timeline. Your ingest key and ingest secret are on your app's Connectors → Backend events page.
Endpoint
POST https://whyitchanged.com/ingest/<ingest_key>/events
Content-Type: application/json
Authentication
Use either one:
- Bearer:
Authorization: Bearer <ingest secret> - Signed body:
X-WhyItChanged-Signature: sha256=<hex HMAC-SHA256 of the raw body, keyed with the ingest secret>
Request body
An object with an events array (a bare array or a single event also works). Up to 500 events and 1 MB per request.
{"events": [
{"type": "signup", "user_id": "u_123", "ts": "2026-11-01T10:00:00Z", "channel": "web"},
{"type": "create_tap", "user_id": "u_123"},
{"type": "purchase", "user_id": "u_123", "id": "evt_1", "amount": 14.99, "net": 10.49,
"product_id": "pack_1499", "transaction_id": "2000000123"},
{"type": "error", "user_id": "u_123", "message": "Export failed: timeout"},
{"type": "purchase_failed", "user_id": "u_123", "message": "SKErrorUnknown"},
{"type": "push_campaign", "title": "New templates push", "detail": "4,800 recipients"},
{"type": "deploy", "title": "api v1.8.2", "id": "deploy-182"}
]}
Event types
- Metrics:
signup,create_tap,purchase,error,crash,bugandpurchase_failedroll up into daily metrics. Errors from users who have paid are listed first under Paying-user problems. - Timeline markers:
release,deploy,push_campaign,noteandad_changeappear on the change timeline. - Any other
snake_casetype is stored as a custom event.
Fields
type(required): snake_case, up to 40 characters.ts: ISO 8601 timestamp. Defaults to now.id: makes retries idempotent; the same id is only stored once.user_id: a pseudonymous id. Please don't send emails or names.amount/net/product_id/transaction_id: for purchases.title/detail/message: shown on markers and in problem lists.
Example
curl -X POST https://whyitchanged.com/ingest/$INGEST_KEY/events \
-H "Authorization: Bearer $INGEST_SECRET" \
-H "Content-Type: application/json" \
-d '{"events":[{"type":"deploy","title":"api v1.8.2","id":"deploy-182"}]}'
A successful response returns counts of the accepted events. Invalid events are reported per index, and the rest still go through.
Other inbound webhooks
- RevenueCat:
/ingest/<ingest_key>/revenuecat. Set the Authorization value in the RevenueCat connector first. - GitHub (releases and successful deployments as markers):
/ingest/<ingest_key>/github, using a webhook secret. - Website snippet (cookie-free pageviews by channel):
<script defer src="https://whyitchanged.com/t.js" data-app="<ingest_key>"></script>