Webhook events you can subscribe to
The full list of webhook event types Journalify emits, with payload schemas and delivery semantics.
Envelope schema
Every webhook payload uses the same envelope. The event-specific fields live under data:
{
"id": "evt_01HXYZABC123",
"type": "story.published",
"occurred_at": "2026-05-23T09:14:22Z",
"tenant_id": "ten_5f3a9c",
"data": {
"// event-specific fields go here, see below": null
}
}- id — unique event id. Use it for idempotency keys in your receiver — Journalify may retry on transient failures.
- type — dot-separated event name. New events may be added at any time; treat unknown types as no-op rather than failing.
- occurred_at — ISO-8601 UTC timestamp when the event was created.
- tenant_id — the newsroom the event belongs to. Useful when one webhook endpoint receives traffic from multiple tenants.
- data — the event-specific body. Fields are versioned additively; do not assume an exhaustive shape.
Story events
Emitted as a story moves through the editorial workflow:
- story.published — a story transitions to published
- story.unpublished — a previously published story is taken down
- story.updated — title, body, byline, or metadata of a published story changed
- story.deleted — a story is permanently deleted
Example data for story.published:
{
"id": "sty_8a2f1c",
"headline": "Mayor announces 2026 budget",
"lede": "$2.3B in new investments across transport and education.",
"byline": ["usr_4567"],
"department_id": "politics",
"tags": ["politics", "budget"],
"published_at": "2026-05-23T09:14:22Z",
"url": "https://cloud.journalify.app/news/sty_8a2f1c"
}Today data.url points to the canonical editorial draft URL inside the Journalify newsroom. Once social auto-post ships, data.canonical_url will also be present and point to your own published site URL — use canonical_url when present, fall back to url otherwise.
Media events
- media.uploaded — a new asset is added to the media library
- media.deleted — an asset is removed
Example data for media.uploaded:
{
"id": "med_b71c4e",
"kind": "image",
"mime_type": "image/jpeg",
"size_bytes": 482910,
"width": 4032,
"height": 3024,
"caption": "Mayor at press conference",
"credit": "Sarah Khalifa / Desert News",
"uploaded_at": "2026-05-23T09:11:08Z",
"uploaded_by": "usr_4567"
}Assignment events
- assignment.created — an editor assigns a story idea to a reporter
- assignment.completed — the reporter marks the assignment done (or the linked story is published)
Example data for assignment.created:
{
"id": "asn_3e9b7a",
"title": "2026 budget reaction from opposition",
"brief": "Get quotes from the three main opposition figures within 4 hours.",
"due_at": "2026-05-23T13:00:00Z",
"assignee_id": "usr_8821",
"assigner_id": "usr_4567",
"department_id": "politics"
}Audit events
Account-level security events. Useful for piping into your SIEM:
- api_key.created — a new API key is issued for the tenant
- api_key.revoked — an API key is revoked or expires
Example data for api_key.created:
{
"api_key_id": "jnf_abc12345",
"name": "Mailchimp digest",
"scopes": ["stories:read"],
"created_by": "usr_4567",
"expires_at": null
}Delivery semantics
- At-least-once — a single event may be delivered more than once on retry. De-duplicate on event id.
- Per-subscription ordering is best-effort. Do not rely on receiving story.published strictly before story.updated for the same story id — instead, compare occurred_at in your handler.
- A failed delivery does not block subsequent events for the same subscription.
Was this helpful?
Can't find what you need, or spot something wrong? Let us know — every article is improved based on customer feedback.
Contact support