System Webhooks
Notify your own services about what happens across the whole instance: new users and workspaces, subscription changes, payments, trials and the first steps customers take.
Overview
Webhooks created in a workspace only hear about that workspace: its posts and its social accounts. System webhooks listen to the whole Mixpost Enterprise instance. Use them to keep a CRM in sync, alert your team about a failed payment, or send lifecycle emails from your email platform:
- a welcome email;
- a reminder before a trial ends;
- a nudge to connect a first account;
- a note asking why a customer left.
Every event carries what such an email needs, such as who to write to, which plan they are on and the links to send them to. Your service never has to call Mixpost back.
Create a system webhook
Open the Admin Console and click Webhooks under System. Then click Create webhook.
The form, the deliveries, the retries and the signature work exactly as they do for workspace webhooks. Only the list of events differs.
Payload
Every request has the same envelope as a workspace webhook: the event name and its data.
{
"event": "workspace.trial_ending",
"data": {}
}
The headers are the same too: Content-Type, X-Request-Source and, when the webhook has a secret,
X-Signature.
A few things hold for every event:
- Dates come in two formats.
- Fields that belong to a user, workspace, subscription or receipt are formatted for reading, for
example
"Oct 29, 2026". - Fields that belong to the event itself are ISO 8601 in UTC, for example
"2026-10-29T10:00:00+00:00". Use these when you compare or schedule.
- Fields that belong to a user, workspace, subscription or receipt are formatted for reading, for
example
- Workspaces are identified by their
uuid. A workspace'sowneris the user who pays for it and the one to write to. - Amounts are in the currency set under Billing.
plan.currencyrepeats it where a plan appears.
Lifecycle fields
The trial, onboarding and publishing events, and subscription.ended and
subscription.downgraded_to_free, share a common set of fields about the workspace.
| Field | Description |
|---|---|
workspace | The workspace, with its owner, its subscriptions and, during a trial without a card, generic_subscription. |
trial.card_on_file | true for a trial started with a card at checkout, false for a trial without a card. |
trial.ends_at | When the trial ends, or null. |
plan | The plan the workspace is on or trying: id, name, monthly_amount, yearly_amount, currency. |
usage.accounts_count | How many social accounts are connected. |
usage.scheduled_posts_count | How many posts are scheduled. |
urls.upgrade | The page where the owner chooses a plan. |
urls.billing | The workspace's Subscription page. |
urls.accounts | The page where social accounts are connected. |
When events are sent
-
Most events are sent the moment they happen.
-
Lifecycle events are found by a check that runs every hour:
workspace.trial_endingworkspace.trial_endedworkspace.no_accounts_connectedworkspace.no_posts_scheduledsubscription.trial_convertedsubscription.ended
They need the scheduler running. Each is sent once per workspace and occurrence, however often the check runs.
-
Workspaces with unlimited access never receive the trial, billing and onboarding events. This includes the installer's workspace and any workspace an admin gives unlimited access to.
workspace.post_failedis the exception.
Events
| Event | Sent when |
|---|---|
user.created | A user signs up or is created. |
user.email_verified | A user verifies their email address. |
user.deleted | A user is deleted. |
workspace.created | A workspace is created. |
workspace.deleted | A workspace is deleted. |
workspace.trial_ending | A trial ends in 3 days, and again in 1 day. |
workspace.trial_ended | A trial without a card ended without a subscription. |
workspace.no_accounts_connected | A day after a workspace was created, it has no social account. |
workspace.no_posts_scheduled | A day after its first social account, a workspace has no post. |
workspace.first_post_published | A workspace publishes its first post. |
workspace.post_failed | A post fails to publish to an account. |
subscription.created | The payment platform reports a new subscription. |
subscription.updated | The payment platform reports a change to a subscription. |
subscription.trial_converted | A trial turned into a paid subscription. |
subscription.cancel_requested | The owner cancels from the Subscription page. |
subscription.canceled | The payment platform reports a cancellation. |
subscription.ended | A workspace loses access because its subscription ended or paused. |
subscription.downgraded_to_free | A workspace moves to the free plan instead of losing access. |
subscription.payment_succeeded | A payment goes through. |
subscription.payment_failed | A payment fails. |
Users
user.created
A user signs up, signs in for the first time through single sign-on, or is created by an admin.
from_admin is true when an admin created them in the console.
Example payload
{
"event": "user.created",
"data": {
"user": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": null,
"created_at": "Oct 15, 09:08am"
},
"from_admin": false
}
}
user.email_verified
A user verifies their email address.
Example payload
{
"event": "user.email_verified",
"data": {
"user": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
}
}
}
user.deleted
A user is deleted. What they were is taken before the deletion, so the payload is complete even though the user no longer exists.
| Field | Description |
|---|---|
deleted_by | user when they deleted their own account, admin when an admin deleted them, unverified when the daily cleanup removed them for never verifying their email. |
deleted_workspaces | The uuid of each workspace deleted together with the account. Only when the user deleted their own account; otherwise an empty list. |
deleted_at | When it happened. |
When a user deletes their own account, each workspace they owned first sends
workspace.deleted with deleted_by: account_deletion, then user.deleted
follows. To write to the user once, react to user.deleted and skip workspace.deleted when
deleted_by is account_deletion.
Example payload
{
"event": "user.deleted",
"data": {
"user": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"deleted_workspaces": ["9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13"],
"deleted_by": "user",
"deleted_at": "2026-10-22T10:00:00+00:00"
}
}
Workspaces
workspace.created
A workspace is created, at sign-up, by a user from their profile, or by an admin. from_admin is
true when an admin created it in the console.
Example payload
{
"event": "workspace.created",
"data": {
"workspace": {
"uuid": "9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13",
"name": "Acme Studio",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 15, 09:10am"
},
"from_admin": false
}
}
workspace.deleted
A workspace is deleted. Its subscription is cancelled at the same time.
| Field | Description |
|---|---|
deleted_by | owner from the workspace settings, admin from the console or the API, account_deletion when its owner deleted their account. |
deleted_at | When it happened. |
Example payload
{
"event": "workspace.deleted",
"data": {
"workspace": {
"uuid": "6d1f3a9c-2e7b-4c58-a0d4-8b3e5f1c7a92",
"name": "Acme Labs",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 14, 08:00am",
"subscriptions": [],
"generic_subscription": {
"name": "Studio",
"free": false,
"trial_ends_at": "Oct 21, 2026",
"has_trial": true,
"has_expired_trial": true,
"remaining_trial_days": 0
}
},
"deleted_by": "owner",
"deleted_at": "2026-10-22T10:00:00+00:00"
}
}
Trials and onboarding
workspace.trial_ending
A trial ends in 3 days, and again when it ends in 1 day. days_left is 3 or 1. It is sent for
both kinds of trial:
- With a card on file (
trial.card_on_file: true), the subscription starts and the card is charged when the trial ends. - Without a card, the owner has to choose a plan before then.
If a trial is extended, its reminders are sent again for the new end date.
Example payload
{
"event": "workspace.trial_ending",
"data": {
"workspace": {
"uuid": "9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13",
"name": "Acme Studio",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 15, 09:10am",
"subscriptions": [
{
"name": "default",
"platform_subscription_id": "sub_01jabc2def3ghi",
"platform_plan_id": "pri_01studio_monthly",
"plan": null,
"status": "trialing",
"recurring": false,
"trial_ends_at": "Oct 29, 2026",
"paused_from": null,
"ends_at": null
}
],
"generic_subscription": null
},
"trial": {
"card_on_file": true,
"ends_at": "2026-10-29T10:00:00+00:00"
},
"plan": {
"id": 1,
"name": "Studio",
"monthly_amount": 29,
"yearly_amount": 290,
"currency": "USD"
},
"usage": {
"accounts_count": 0,
"scheduled_posts_count": 0
},
"urls": {
"upgrade": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/upgrade",
"billing": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/billing",
"accounts": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/accounts"
},
"days_left": 3
}
}
workspace.trial_ended
A trial without a card ended and the owner did not subscribe. The workspace is locked until they choose a plan.
When the instance has an active free plan, the workspace moves to it instead and sends
subscription.downgraded_to_free with from_trial: true. In that
case workspace.trial_ended is not sent.
A trial with a card does not end this way. When it ends, the card is charged, which sends
subscription.trial_converted, or the payment fails, which sends
subscription.payment_failed.
Example payload
{
"event": "workspace.trial_ended",
"data": {
"workspace": {
"uuid": "6d1f3a9c-2e7b-4c58-a0d4-8b3e5f1c7a92",
"name": "Acme Labs",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 14, 08:00am",
"subscriptions": [],
"generic_subscription": {
"name": "Studio",
"free": false,
"trial_ends_at": "Oct 21, 2026",
"has_trial": true,
"has_expired_trial": true,
"remaining_trial_days": 0
}
},
"trial": {
"card_on_file": false,
"ends_at": "2026-10-21T10:00:00+00:00"
},
"plan": {
"id": 1,
"name": "Studio",
"monthly_amount": 29,
"yearly_amount": 290,
"currency": "USD"
},
"usage": {
"accounts_count": 0,
"scheduled_posts_count": 0
},
"urls": {
"upgrade": "https://mixpost.example.com/6d1f3a9c-2e7b-4c58-a0d4-8b3e5f1c7a92/upgrade",
"billing": "https://mixpost.example.com/6d1f3a9c-2e7b-4c58-a0d4-8b3e5f1c7a92/billing",
"accounts": "https://mixpost.example.com/6d1f3a9c-2e7b-4c58-a0d4-8b3e5f1c7a92/accounts"
}
}
}
workspace.no_accounts_connected
A day after the workspace was created, it still has no social account connected.
Example payload
{
"event": "workspace.no_accounts_connected",
"data": {
"workspace": {
"uuid": "9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13",
"name": "Acme Studio",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 15, 09:10am",
"subscriptions": [
{
"name": "default",
"platform_subscription_id": "sub_01jabc2def3ghi",
"platform_plan_id": "pri_01studio_monthly",
"plan": null,
"status": "trialing",
"recurring": false,
"trial_ends_at": "Oct 29, 2026",
"paused_from": null,
"ends_at": null
}
],
"generic_subscription": null
},
"trial": {
"card_on_file": true,
"ends_at": "2026-10-29T10:00:00+00:00"
},
"plan": {
"id": 1,
"name": "Studio",
"monthly_amount": 29,
"yearly_amount": 290,
"currency": "USD"
},
"usage": {
"accounts_count": 0,
"scheduled_posts_count": 0
},
"urls": {
"upgrade": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/upgrade",
"billing": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/billing",
"accounts": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/accounts"
}
}
}
workspace.no_posts_scheduled
A day after its first social account was connected, the workspace has nothing scheduled, published or
attempted. Drafts do not count. first_account_connected_at is when that first account was connected.
Example payload
{
"event": "workspace.no_posts_scheduled",
"data": {
"workspace": {
"uuid": "9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13",
"name": "Acme Studio",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 15, 09:10am",
"subscriptions": [
{
"name": "default",
"platform_subscription_id": "sub_01jabc2def3ghi",
"platform_plan_id": "pri_01studio_monthly",
"plan": null,
"status": "trialing",
"recurring": false,
"trial_ends_at": "Oct 29, 2026",
"paused_from": null,
"ends_at": null
}
],
"generic_subscription": null
},
"trial": {
"card_on_file": true,
"ends_at": "2026-10-29T10:00:00+00:00"
},
"plan": {
"id": 1,
"name": "Studio",
"monthly_amount": 29,
"yearly_amount": 290,
"currency": "USD"
},
"usage": {
"accounts_count": 1,
"scheduled_posts_count": 0
},
"urls": {
"upgrade": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/upgrade",
"billing": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/billing",
"accounts": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/accounts"
},
"first_account_connected_at": "2026-10-20T11:30:00+00:00"
}
}
workspace.first_post_published
A workspace publishes its first post. A post that goes out to several accounts sends this once, for
the first account it reaches. post.url opens the post in Mixpost, and account is the social account
it went out to.
Example payload
{
"event": "workspace.first_post_published",
"data": {
"workspace": {
"uuid": "9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13",
"name": "Acme Studio",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 15, 09:10am",
"subscriptions": [
{
"name": "default",
"platform_subscription_id": "sub_01jabc2def3ghi",
"platform_plan_id": "pri_01studio_monthly",
"plan": null,
"status": "trialing",
"recurring": false,
"trial_ends_at": "Oct 29, 2026",
"paused_from": null,
"ends_at": null
}
],
"generic_subscription": null
},
"trial": {
"card_on_file": true,
"ends_at": "2026-10-29T10:00:00+00:00"
},
"plan": {
"id": 1,
"name": "Studio",
"monthly_amount": 29,
"yearly_amount": 290,
"currency": "USD"
},
"usage": {
"accounts_count": 1,
"scheduled_posts_count": 0
},
"urls": {
"upgrade": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/upgrade",
"billing": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/billing",
"accounts": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/accounts"
},
"post": {
"uuid": "5c0e8a7d-3b19-4f62-9d84-7a1e2c6b0f53",
"url": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/posts/5c0e8a7d-3b19-4f62-9d84-7a1e2c6b0f53"
},
"account": {
"id": 1,
"name": "Acme Studio",
"provider": "mastodon"
}
}
}
workspace.post_failed
A post fails to publish to an account. A post going out to several accounts sends one event for each account it fails on. Workspaces with unlimited access receive it too.
| Field | Description |
|---|---|
post.url | Opens the post in Mixpost. |
account | The social account it failed on. |
error | The reason the social network gave, when there is one. |
is_first_failure | true when the workspace has never published a post, so this is how its first attempt went. |
failures_last_24h | How many posts failed in the workspace in the last 24 hours, this one included. |
Example payload
{
"event": "workspace.post_failed",
"data": {
"workspace": {
"uuid": "9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13",
"name": "Acme Studio",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 15, 09:10am",
"subscriptions": [
{
"name": "default",
"platform_subscription_id": "sub_01jabc2def3ghi",
"platform_plan_id": "pri_01studio_monthly",
"plan": null,
"status": "trialing",
"recurring": false,
"trial_ends_at": "Oct 29, 2026",
"paused_from": null,
"ends_at": null
}
],
"generic_subscription": null
},
"trial": {
"card_on_file": true,
"ends_at": "2026-10-29T10:00:00+00:00"
},
"plan": {
"id": 1,
"name": "Studio",
"monthly_amount": 29,
"yearly_amount": 290,
"currency": "USD"
},
"usage": {
"accounts_count": 1,
"scheduled_posts_count": 0
},
"urls": {
"upgrade": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/upgrade",
"billing": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/billing",
"accounts": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/accounts"
},
"post": {
"uuid": "5c0e8a7d-3b19-4f62-9d84-7a1e2c6b0f53",
"url": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/posts/5c0e8a7d-3b19-4f62-9d84-7a1e2c6b0f53"
},
"account": {
"id": 1,
"name": "Acme Studio",
"provider": "mastodon"
},
"error": "The access token has expired.",
"is_first_failure": true,
"failures_last_24h": 1
}
}
Subscriptions
subscription.created
The payment platform reports a new subscription, usually right after checkout. A subscription that
starts with a card trial arrives with status: trialing.
status is one of active, trialing, past_due, paused or canceled. plan.cycle is monthly
or yearly.
Example payload
{
"event": "subscription.created",
"data": {
"name": "default",
"workspace": {
"uuid": "9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13",
"name": "Acme Studio",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 15, 09:10am"
},
"platform_subscription_id": "sub_01jabc2def3ghi",
"platform_plan_id": "pri_01studio_monthly",
"plan": {
"id": 1,
"name": "Studio",
"amount": 29,
"cycle": "monthly"
},
"status": "trialing",
"recurring": false,
"trial_ends_at": "Oct 29, 2026",
"paused_from": null,
"ends_at": null
}
}
subscription.updated
The payment platform reports a change to a subscription: a new plan or cycle, a status change, a pause
or a resume. The payload is the subscription as it is now, in the same shape as
subscription.created.
Example payload
{
"event": "subscription.updated",
"data": {
"name": "default",
"workspace": {
"uuid": "9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13",
"name": "Acme Studio",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 15, 09:10am"
},
"platform_subscription_id": "sub_01jabc2def3ghi",
"platform_plan_id": "pri_01studio_monthly",
"plan": {
"id": 1,
"name": "Studio",
"amount": 29,
"cycle": "monthly"
},
"status": "trialing",
"recurring": false,
"trial_ends_at": "Oct 29, 2026",
"paused_from": null,
"ends_at": null
}
}
subscription.trial_converted
A trial turned into a paid subscription:
- A card trial was charged at its end:
card_on_file_during_trial: true. - A workspace on a trial without a card subscribed:
card_on_file_during_trial: false.
Example payload
{
"event": "subscription.trial_converted",
"data": {
"subscription": {
"name": "default",
"workspace": {
"uuid": "9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13",
"name": "Acme Studio",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 15, 09:10am"
},
"platform_subscription_id": "sub_01jabc2def3ghi",
"platform_plan_id": "pri_01studio_monthly",
"plan": {
"id": 1,
"name": "Studio",
"amount": 29,
"cycle": "monthly"
},
"status": "active",
"recurring": true,
"trial_ends_at": "Oct 22, 2026",
"paused_from": null,
"ends_at": null
},
"card_on_file_during_trial": true
}
}
subscription.cancel_requested
The owner cancels from the workspace's Subscription page. The subscription keeps running until
ends_at, the end of the period already paid for.
| Field | Description |
|---|---|
reason | What the owner picked: too_expensive, missing_features, not_using, switched_service, technical_issues, temporary or other. |
comment | What they wrote, or null. |
ends_at | When the subscription ends. |
billing_url | The workspace's Subscription page, where the owner can resume before it ends. |
Example payload
{
"event": "subscription.cancel_requested",
"data": {
"subscription": {
"name": "default",
"workspace": {
"uuid": "9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13",
"name": "Acme Studio",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 15, 09:10am"
},
"platform_subscription_id": "sub_01jabc2def3ghi",
"platform_plan_id": "pri_01studio_monthly",
"plan": {
"id": 1,
"name": "Studio",
"amount": 29,
"cycle": "monthly"
},
"status": "active",
"recurring": false,
"trial_ends_at": "Oct 22, 2026",
"paused_from": null,
"ends_at": "Nov 22, 2026"
},
"reason": "too_expensive",
"comment": "Too much for a team of two.",
"ends_at": "2026-11-22T09:58:00+00:00",
"billing_url": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/billing"
}
}
subscription.canceled
The payment platform reports that a subscription was cancelled. That can be the owner cancelling from
Mixpost or from the platform's portal, or the platform cancelling it after failed payments. The payload
is the subscription, in the same shape as subscription.created.
Example payload
{
"event": "subscription.canceled",
"data": {
"name": "default",
"workspace": {
"uuid": "9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13",
"name": "Acme Studio",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 15, 09:10am"
},
"platform_subscription_id": "sub_01jabc2def3ghi",
"platform_plan_id": "pri_01studio_monthly",
"plan": {
"id": 1,
"name": "Studio",
"amount": 29,
"cycle": "monthly"
},
"status": "canceled",
"recurring": false,
"trial_ends_at": "Oct 22, 2026",
"paused_from": null,
"ends_at": "Nov 22, 2026"
}
}
subscription.ended
A workspace actually loses access:
- a cancelled subscription reached its end date (
reason: canceled); - a pause took effect (
reason: paused).
It is not sent when the workspace resumed, subscribed again or moved to the free plan.
| Field | Description |
|---|---|
reason | canceled or paused. |
ended_at | When access ended. |
was_trial | true when a card trial was cancelled before its first payment. |
cancellation | The reason and comment the owner gave when cancelling, or null when they gave none or it paused. |
Example payload
{
"event": "subscription.ended",
"data": {
"workspace": {
"uuid": "9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13",
"name": "Acme Studio",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 15, 09:10am",
"subscriptions": [
{
"name": "default",
"platform_subscription_id": "sub_01jabc2def3ghi",
"platform_plan_id": "pri_01studio_monthly",
"plan": null,
"status": "canceled",
"recurring": false,
"trial_ends_at": "Oct 22, 2026",
"paused_from": null,
"ends_at": "Nov 22, 2026"
}
],
"generic_subscription": null
},
"trial": {
"card_on_file": true,
"ends_at": "2026-10-22T09:58:00+00:00"
},
"plan": {
"id": 1,
"name": "Studio",
"monthly_amount": 29,
"yearly_amount": 290,
"currency": "USD"
},
"usage": {
"accounts_count": 1,
"scheduled_posts_count": 0
},
"urls": {
"upgrade": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/upgrade",
"billing": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/billing",
"accounts": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/accounts"
},
"subscription": {
"name": "default",
"workspace": {
"uuid": "9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13",
"name": "Acme Studio",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 15, 09:10am",
"subscriptions": [
{
"name": "default",
"platform_subscription_id": "sub_01jabc2def3ghi",
"platform_plan_id": "pri_01studio_monthly",
"plan": null,
"status": "canceled",
"recurring": false,
"trial_ends_at": "Oct 22, 2026",
"paused_from": null,
"ends_at": "Nov 22, 2026"
}
],
"generic_subscription": null
},
"platform_subscription_id": "sub_01jabc2def3ghi",
"platform_plan_id": "pri_01studio_monthly",
"plan": {
"id": 1,
"name": "Studio",
"amount": 29,
"cycle": "monthly"
},
"status": "canceled",
"recurring": false,
"trial_ends_at": "Oct 22, 2026",
"paused_from": null,
"ends_at": "Nov 22, 2026"
},
"reason": "canceled",
"ended_at": "2026-11-22T09:58:00+00:00",
"was_trial": false,
"cancellation": {
"reason": "too_expensive",
"comment": "Too much for a team of two."
}
}
}
subscription.downgraded_to_free
A workspace moves to the free plan instead of losing access. This happens when a paid subscription
ends, or a trial without a card expires, and the instance has an active free plan. It is sent instead
of subscription.ended or workspace.trial_ended.
| Field | Description |
|---|---|
previous_plan | The name of the plan the workspace was on. |
ended_at | When that plan ended. |
from_trial | true when it was a trial without a card that expired. |
plan in the lifecycle fields is now the free plan.
Example payload
{
"event": "subscription.downgraded_to_free",
"data": {
"workspace": {
"uuid": "9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13",
"name": "Acme Studio",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 15, 09:10am",
"subscriptions": [
{
"name": "default",
"platform_subscription_id": "sub_01jabc2def3ghi",
"platform_plan_id": "pri_01studio_monthly",
"plan": null,
"status": "canceled",
"recurring": false,
"trial_ends_at": "Oct 22, 2026",
"paused_from": null,
"ends_at": "Nov 22, 2026"
}
],
"generic_subscription": {
"name": "Free",
"free": true,
"trial_ends_at": null,
"has_trial": false,
"has_expired_trial": false,
"remaining_trial_days": 0
}
},
"trial": {
"card_on_file": true,
"ends_at": "2026-10-22T09:58:00+00:00"
},
"plan": {
"id": 1,
"name": "Studio",
"monthly_amount": 29,
"yearly_amount": 290,
"currency": "USD"
},
"usage": {
"accounts_count": 1,
"scheduled_posts_count": 0
},
"urls": {
"upgrade": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/upgrade",
"billing": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/billing",
"accounts": "https://mixpost.example.com/9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13/accounts"
},
"previous_plan": "Studio",
"ended_at": "2026-11-22T09:58:00+00:00",
"from_trial": false
}
}
subscription.payment_succeeded
A payment goes through, a renewal included. The payload is the receipt.
Example payload
{
"event": "subscription.payment_succeeded",
"data": {
"uuid": "4e8a1c2b-7d3f-4a9e-8b5c-1f6d2e9a0b37",
"workspace": {
"uuid": "9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13",
"name": "Acme Studio",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 15, 09:10am"
},
"transaction_id": "txn_01jxyz9klm8nop",
"invoice_number": "1234-56789",
"amount": "29",
"tax": "0",
"currency": "USD",
"receipt_url": null,
"description": "Studio - Monthly",
"created_at": "Oct 22, 2026",
"paid_at": "Oct 22, 2026",
"paid_at_raw": "2026-10-22 09:58"
}
}
subscription.payment_failed
A payment fails. The payment platform usually retries before it cancels the subscription. The payload
is the workspace itself, with its owner.
Example payload
{
"event": "subscription.payment_failed",
"data": {
"uuid": "9b2c7e41-5f3a-4d8e-b1c6-2a7f9e0d4c13",
"name": "Acme Studio",
"avatar": null,
"owner_id": 1,
"owner": {
"id": 1,
"name": "Jane Doe",
"email": "jane@example.com",
"avatar": null,
"is_admin": false,
"settings": [],
"email_verified_at": "Oct 15, 09:12am",
"created_at": "Oct 15, 09:08am"
},
"access_status": "subscription",
"created_at": "Oct 15, 09:10am"
}
}