Events
Each delivery wraps an event-specific payload in the data field of the envelope. Everything below describes the contents of data. All payloads are snake_case.
Eleven event names are defined. Seven are emitted today; the other four are reserved and never fire — they are listed at the bottom so you do not build against them.
content.created
Section titled “content.created”Fired when a new content object appears, whether from POST /api/v1/content or from the dashboard.
{ "content": { "id": "9f2c8e7b-1a3d-4f60-b2c1-7e5a9d3c4b81", "object": "content", "caption": "Ship faster with NativPost.", "status": "draft", "target_platforms": ["instagram"], "scheduled_for": null }}content is the full serialized object — every field in the content model, not the abbreviated form shown here.
content.updated
Section titled “content.updated”Fired on any successful PATCH /api/v1/content/{id}. Payload is the full updated object under content, same shape as above.
content.approved
Section titled “content.approved”Fired alongside content.updated whenever a PATCH body sets status to approved, and by POST /api/v1/content/{id}/publish.
Through the v1 API this is not a transition event: patching status: "approved" onto an item that is already approved fires it again. Deduplicate on the envelope’s delivery id if that matters to you. (Dashboard-originated approvals do check for an actual transition, so the two paths differ.)
{ "content": { "id": "9f2c8e7b-...", "object": "content", "status": "approved" }}content.published
Section titled “content.published”Fired once per content item after at least one platform accepts the post. platforms has one entry per delivery attempt.
{ "content": { "id": "9f2c8e7b-1a3d-4f60-b2c1-7e5a9d3c4b81", "object": "content" }, "published_at": "2026-07-19T13:00:03Z", "platforms": [ { "platform": "instagram", "success": true, "platform_post_id": "17987654...", "error": null }, { "platform": "tiktok", "success": false, "platform_post_id": null, "error": "Media format rejected" } ]}Here content is a stub — just id and object, not the full object. Fetch the resource if you need its fields.
A partial success still fires content.published: the item is published as long as one leg succeeded, and the failed legs appear in the same array with success: false.
content.publish_failed
Section titled “content.publish_failed”Fired when every targeted platform rejected the post.
{ "content": { "id": "9f2c8e7b-1a3d-4f60-b2c1-7e5a9d3c4b81", "object": "content" }, "failed_at": "2026-07-19T13:00:03Z", "platforms": [ { "platform": "instagram", "success": false, "error": "Media format rejected" }, { "platform": "tiktok", "success": false, "error": "Media format rejected" } ]}Two differences from content.published: the timestamp is failed_at, and the platforms entries carry no platform_post_id key at all — it is absent, not null.
The content item itself returns to approved, not to a failure status. See Statuses.
content.deleted
Section titled “content.deleted”Fired when content is archived.
The payload shape depends on origin. DELETE /api/v1/content/{id} sends the id at the top level:
{ "id": "9f2c8e7b-1a3d-4f60-b2c1-7e5a9d3c4b81" }Dashboard deletions nest it instead:
{ "content": { "id": "9f2c8e7b-1a3d-4f60-b2c1-7e5a9d3c4b81", "object": "content" } }Handle both — read data.id ?? data.content.id.
campaign.launched
Section titled “campaign.launched”Fired when a campaign transitions to active via POST /api/v1/campaigns/{id}/launch.
{ "campaign": { "id": "4b7f2a91-c3d8-4e56-9a07-1f2b3c4d5e6f", "object": "campaign", "name": "Product launch week", "status": "active", "total_posts": 10, "generated_posts": 0 }}campaign is the full serialized campaign. There are no scheduled_posts or skipped_posts fields — generation has not started when this fires. Poll the campaign and watch generated_posts.
social_account.disconnected
Section titled “social_account.disconnected”Fired when Meta calls the deauthorize callback or the data-deletion callback.
{ "platform": "instagram", "account": { "platform_user_id": "17841400000000000", "platform_username": "acme.studio" }, "reason": "deauthorized"}reason is either deauthorized (the user removed the app; accounts are marked inactive) or data_deletion (a deletion request; the account rows are removed). Those are the only two values emitted.
The payload has no account_type field, and one event fires per affected workspace.
Reserved, never emitted
Section titled “Reserved, never emitted”These names are accepted in an endpoint’s events subscription list, but nothing in the platform fires them today:
campaign.completedcampaign.pausedsocial_account.connected
Subscribing to them is harmless and silently receives nothing. Do not build logic that waits on one — in particular, there is no event for a successful connection, so poll GET /api/v1/social-accounts if you need to detect new connections.
Subscribing
Section titled “Subscribing”An endpoint with an empty events array receives every event, current and future. Naming events explicitly is the safer default. Endpoints are created and edited in the dashboard under Settings → Webhooks; the API can only list them. See Overview.