Webhook events
Every event Inkwave sends to a webhook endpoint, what makes it fire, the fields of its data and an example delivery.
Inkwave sends these events to your webhook endpoints. An endpoint receives only the events it is subscribed to. To set one up, see the Webhooks guide; to check that a delivery really came from Inkwave, see Webhook signatures and delivery.
This page is generated from the event list in Inkwave's code, so it always matches what is sent.
The delivery
Every delivery is an HTTPS POST with a JSON body. The body has the same four fields for every event:
| Field | Type | Description |
|---|---|---|
event_type | string | The event's name, such as post.sent. Also sent in the X-Inkwave-Event header. |
created_at | string | When the delivery was made, as an ISO 8601 timestamp in UTC. |
is_test | boolean | true for a test event sent from the webhooks page, false for a real one. |
data | object | The event's fields, listed under each event below. |
Fields may be added to data over time, so ignore fields you don't recognise rather than rejecting the delivery. A delivery carries no id of its own.
Test events
Send Test Event on an endpoint's page sends one of its event types with is_test set to true. A test delivery's data is not the event's fields: it is always the same two fields, whatever the event.
| Field | Type | Description |
|---|---|---|
test | boolean | Always true. |
publication_id | string | Your publication. |
{
"event_type": "subscription.created",
"created_at": "2026-01-15T09:30:00.000Z",
"is_test": true,
"data": {
"test": true,
"publication_id": "7d2f6b1a-9c4e-4b3a-8f5d-2e6a1c9b4f7e"
}
}
Events
| Event | Description |
|---|---|
| subscription.created | A new reader joins your list. |
| subscription.deleted | A reader unsubscribes or is unsubscribed. |
| subscription.upgraded | A reader starts a paid subscription. |
| subscription.downgraded | A paid subscription is cancelled from your dashboard. |
| subscription.tier.created | A reader starts a paid subscription (sent with subscription.upgraded). |
| subscription.tier.deleted | A reader's paid subscription has ended in Stripe. |
| post.sent | A newsletter post finishes sending by email. |
| survey.response_submitted | A subscriber submits a survey response. |
| poll.response_submitted | A reader answers a poll. |
| invoice.payment_succeeded | A reader's payment for a paid subscription succeeds. |
| invoice.payment_failed | A reader's payment for a paid subscription fails. |
subscription.created
Subscription created. A new reader joins your list.
When it fires: A new reader is added to your list: a sign-up, a reader you add by hand, or an access request you approve. If your publication asks readers to confirm their email, sent once, when they confirm. Not sent when a former subscriber rejoins, or when someone new joins straight onto a paid plan (that sends subscription.upgraded).
Data
| Field | Type | Description |
|---|---|---|
publication_subscriber_id | string | The reader's membership of this publication. |
subscriber_id | string | The reader. The same person has the same id in every publication they read. |
email | string | The reader's email address. |
Example delivery
{
"event_type": "subscription.created",
"created_at": "2026-01-15T09:30:00.000Z",
"is_test": false,
"data": {
"publication_subscriber_id": "5f0c2a8e-1b3d-4c6f-9a7e-2d4b6c8e0a1f",
"subscriber_id": "9b1e4d7a-3c5f-4e8b-a2d6-7f9c1e3b5d8a",
"email": "reader@example.com"
}
}
subscription.deleted
Subscription deleted. A reader unsubscribes or is unsubscribed.
When it fires: A reader unsubscribes, from an email link or their preferences page, or you unsubscribe them.
Data
| Field | Type | Description |
|---|---|---|
publication_subscriber_id | string | The reader's membership of this publication. |
subscriber_id | string | The reader. The same person has the same id in every publication they read. |
email | string | The reader's email address. |
Example delivery
{
"event_type": "subscription.deleted",
"created_at": "2026-01-15T09:30:00.000Z",
"is_test": false,
"data": {
"publication_subscriber_id": "5f0c2a8e-1b3d-4c6f-9a7e-2d4b6c8e0a1f",
"subscriber_id": "9b1e4d7a-3c5f-4e8b-a2d6-7f9c1e3b5d8a",
"email": "reader@example.com"
}
}
subscription.upgraded
Subscription upgraded. A reader starts a paid subscription.
When it fires: A reader completes a paid checkout, including one that starts with a free trial. Always sent together with subscription.tier.created.
Data
| Field | Type | Description |
|---|---|---|
publication_subscriber_id | string | The reader's membership of this publication. |
subscriber_id | string | The reader. The same person has the same id in every publication they read. |
email | string | The reader's email address. |
plan_id | string | The paid plan the reader checked out on. |
Example delivery
{
"event_type": "subscription.upgraded",
"created_at": "2026-01-15T09:30:00.000Z",
"is_test": false,
"data": {
"publication_subscriber_id": "5f0c2a8e-1b3d-4c6f-9a7e-2d4b6c8e0a1f",
"subscriber_id": "9b1e4d7a-3c5f-4e8b-a2d6-7f9c1e3b5d8a",
"email": "reader@example.com",
"plan_id": "c3a7e1f9-5b2d-4a8c-9e6f-1d3b5a7c9e2f"
}
}
subscription.downgraded
Subscription downgraded. A paid subscription is cancelled from your dashboard.
When it fires: You cancel a reader's paid subscription. It is set to end at the close of the current billing period; the reader keeps access until then. A subscription that ends in Stripe sends subscription.tier.deleted instead.
Data
| Field | Type | Description |
|---|---|---|
publication_subscriber_id | string | The reader's membership of this publication. |
subscriber_id | string | The reader. The same person has the same id in every publication they read. |
email | string | The reader's email address. |
Example delivery
{
"event_type": "subscription.downgraded",
"created_at": "2026-01-15T09:30:00.000Z",
"is_test": false,
"data": {
"publication_subscriber_id": "5f0c2a8e-1b3d-4c6f-9a7e-2d4b6c8e0a1f",
"subscriber_id": "9b1e4d7a-3c5f-4e8b-a2d6-7f9c1e3b5d8a",
"email": "reader@example.com"
}
}
subscription.tier.created
Paid tier started. A reader starts a paid subscription (sent with subscription.upgraded).
When it fires: Sent on a paid checkout, alongside subscription.upgraded and with the same data. It is not sent when you create a tier.
Data
| Field | Type | Description |
|---|---|---|
publication_subscriber_id | string | The reader's membership of this publication. |
subscriber_id | string | The reader. The same person has the same id in every publication they read. |
email | string | The reader's email address. |
plan_id | string | The paid plan the reader checked out on. |
Example delivery
{
"event_type": "subscription.tier.created",
"created_at": "2026-01-15T09:30:00.000Z",
"is_test": false,
"data": {
"publication_subscriber_id": "5f0c2a8e-1b3d-4c6f-9a7e-2d4b6c8e0a1f",
"subscriber_id": "9b1e4d7a-3c5f-4e8b-a2d6-7f9c1e3b5d8a",
"email": "reader@example.com",
"plan_id": "c3a7e1f9-5b2d-4a8c-9e6f-1d3b5a7c9e2f"
}
}
subscription.tier.deleted
Paid subscription ended. A reader's paid subscription has ended in Stripe.
When it fires: Stripe reports the subscription deleted: a cancellation reaching the end of its period, or Stripe ending it (for example after failed payments, depending on your Stripe settings). It is not sent when you delete a tier.
Data
| Field | Type | Description |
|---|---|---|
stripe_subscription_id | string | The ended subscription's id in Stripe. |
Example delivery
{
"event_type": "subscription.tier.deleted",
"created_at": "2026-01-15T09:30:00.000Z",
"is_test": false,
"data": {
"stripe_subscription_id": "sub_1QExample000000000000"
}
}
post.sent
Post sent. A newsletter post finishes sending by email.
When it fires: An email send of a post completes. Not sent for a web-only post, a test email, or a send in which every message failed.
Data
| Field | Type | Description |
|---|---|---|
newsletter_id | string | The post. |
publication_id | string | Your publication. |
title | string | The email's subject line (the post title when no subject is set). |
recipient_count | number | How many readers the send was addressed to. Individual messages that bounce or fail are still counted. |
Example delivery
{
"event_type": "post.sent",
"created_at": "2026-01-15T09:30:00.000Z",
"is_test": false,
"data": {
"newsletter_id": "1e5b9d3f-7a2c-4f6e-8b1d-3c5e7a9b2d4f",
"publication_id": "7d2f6b1a-9c4e-4b3a-8f5d-2e6a1c9b4f7e",
"title": "The Monday briefing",
"recipient_count": 1250
}
}
survey.response_submitted
Survey response submitted. A subscriber submits a survey response.
When it fires: A response is submitted by a reader who is a subscriber of this publication. A response that can't be tied to a subscriber does not send it.
Data
| Field | Type | Description |
|---|---|---|
survey_id | string | The survey. |
publication_subscriber_id | string | The reader's membership of this publication. |
subscriber_id | string | The reader. The same person has the same id in every publication they read. |
Example delivery
{
"event_type": "survey.response_submitted",
"created_at": "2026-01-15T09:30:00.000Z",
"is_test": false,
"data": {
"survey_id": "4a8c2e6f-1b3d-4f5a-9c7e-6b2d8f1a3c5e",
"publication_subscriber_id": "5f0c2a8e-1b3d-4c6f-9a7e-2d4b6c8e0a1f",
"subscriber_id": "9b1e4d7a-3c5f-4e8b-a2d6-7f9c1e3b5d8a"
}
}
poll.response_submitted
Poll response submitted. A reader answers a poll.
When it fires: Any recorded poll answer, from an email or the website. A second answer from the same reader to the same poll is refused and sends nothing.
Data
| Field | Type | Description |
|---|---|---|
poll_id | string | The poll. |
option_id | string | The option the reader chose. |
subscriber_id | string or null | The reader, when the answer came from a subscriber of this publication. Null for an answer given with just an email address. |
email | string | The address the answer was given with. |
Example delivery
{
"event_type": "poll.response_submitted",
"created_at": "2026-01-15T09:30:00.000Z",
"is_test": false,
"data": {
"poll_id": "8e2a6c1f-3b5d-4e7a-9f1c-5d3b7e9a2c4f",
"option_id": "2c6e1a5f-9d3b-4c8e-a7f2-4b6d8e1c3a5f",
"subscriber_id": "9b1e4d7a-3c5f-4e8b-a2d6-7f9c1e3b5d8a",
"email": "reader@example.com"
}
}
invoice.payment_succeeded
Payment succeeded. A reader's payment for a paid subscription succeeds.
When it fires: Stripe reports a paid invoice on your connected Stripe account.
Data
| Field | Type | Description |
|---|---|---|
stripe_invoice_id | string | The invoice's id in Stripe. |
stripe_subscription_id | string or null | The Stripe subscription the invoice belongs to, as Stripe reports it. Null, or left out, when Stripe names none. |
amount_paid | number | The amount paid in whole units of currency, not Stripe's smallest unit: 9.5 means 9.50 USD, and a payment of 1000 yen arrives as 1000, because zero-decimal currencies such as JPY have no smaller unit to convert from. |
currency | string | The three-letter ISO currency code, lowercase. |
Example delivery
{
"event_type": "invoice.payment_succeeded",
"created_at": "2026-01-15T09:30:00.000Z",
"is_test": false,
"data": {
"stripe_invoice_id": "in_1QExample000000000000",
"stripe_subscription_id": "sub_1QExample000000000000",
"amount_paid": 9.5,
"currency": "usd"
}
}
invoice.payment_failed
Payment failed. A reader's payment for a paid subscription fails.
When it fires: Stripe reports a failed invoice payment on your connected Stripe account. Stripe retries the payment on its own schedule; each failed attempt it reports sends this again.
Data
| Field | Type | Description |
|---|---|---|
stripe_invoice_id | string | The invoice's id in Stripe. |
stripe_subscription_id | string or null | The Stripe subscription the invoice belongs to, as Stripe reports it. Null, or left out, when Stripe names none. |
Example delivery
{
"event_type": "invoice.payment_failed",
"created_at": "2026-01-15T09:30:00.000Z",
"is_test": false,
"data": {
"stripe_invoice_id": "in_1QExample000000000000",
"stripe_subscription_id": "sub_1QExample000000000000"
}
}
Publisher API
Inkwave's REST API for your own servers, with API keys and scopes, every v1 endpoint, response shapes, limits, errors and curl examples.
Webhook signatures and delivery
Check that a webhook delivery really came from Inkwave, rotate the signing secret, and know what counts as delivered and what happens when a delivery fails.