Early bird discounts live! Claim your offer

billing.trial_ending

The creator's platform trial is about to convert and take its first payment.

project_id is always null for billing events. Fires once per milestone, not once per trial — read hours_remaining to tell the two apart.

When this fires

The creator's own Subscriby trial crosses a reminder milestone on its way to converting. The trial collects a card at checkout and converts by itself, so this is the only advance notice a consumer gets before the first charge appears.

Milestones are configured per deployment (PLATFORM_TRIAL_REMINDER_HOURS) and fire largest-first. The default ladder is 72 hours then 24 hours before trial_ends_at, so a standard 7-day trial produces exactly two events. A milestone wider than the trial itself is skipped rather than fired at signup, so a trial shorter than 72 hours emits only the 24-hour event.

Subscriby emails the creator alongside every emission, and mirrors it to Telegram when their account is linked.

Required ability

billing:read — token must carry this at mint time to subscribe an endpoint to this event.

Payload

{
  "id": "evt_01HX...",
  "type": "billing.trial_ending",
  "created_at": "2026-08-23T09:00:00Z",
  "api_version": "2026-05-01",
  "project_id": null,
  "data": {
    "creator_id": "cre_01HX...",
    "plan_id": "pln_01HX...",
    "subscription_id": "sub_01HX...",
    "trial_ends_at": "2026-08-26T09:00:00Z",
    "hours_remaining": 72,
    "amount": "19.00",
    "currency": "USD",
    "amount_estimated": false
  }
}

Field reference

FieldTypeNotes
idstring ULIDUnique event id, prefixed evt_. Use for idempotent processing.
typestringAlways billing.trial_ending for this event.
created_atISO 8601 timestampServer-side emission time.
api_versionstringWebhook API contract version.
project_idnullAlways null — account-level event.
data.creator_idstring ULIDCreator whose trial is converting.
data.plan_idstring ULID / nullPlatform plan the trial converts onto. null if the tier could not be resolved.
data.subscription_idstring ULIDThe creator's platform subscription row.
data.trial_ends_atISO 8601 timestampWhen the trial converts and the charge is raised.
data.hours_remainingintegerWhich milestone fired — 72 or 24 on the default ladder. Not the live countdown.
data.amountdecimal stringTotal that will be charged, e.g. "19.00". null only when no currency could be resolved.
data.currencystring / nullUppercase ISO 4217 code for amount.
data.amount_estimatedbooleantrue when amount is the plan's list price because the upcoming invoice was unreachable.

Reading amount correctly

When amount_estimated is false, the figure comes from the upcoming Stripe invoice and already includes tax, any discount, and the transaction fees the creator's own sales metered during the trial. It is what will actually be taken.

When amount_estimated is true, Stripe could not be reached and the figure is the plan's list price. Treat it as indicative: do not reconcile against it, and do not surface it as a confirmed charge.

A creator carrying a credit grant or account balance will legitimately see "0.00" — the trial still converts, the invoice is simply covered.

Caveats

  • Not once per trial. The default ladder emits twice. De-duplicate on subscription_id + hours_remaining if your consumer must act only once.
  • A trial the creator cancels before it converts stops emitting — no further milestones fire and no charge is raised.
  • The milestone ladder is deployment configuration, so do not hard-code 72 and 24. Read hours_remaining.
  • hours_remaining is the milestone that fired, not the exact time left. The sweep runs hourly, so the true remaining time is somewhere within an hour below the value.

How is this guide?

On this page

Subscriby is a product designed by you — for you.

No boardroom full of executives deciding what we ships next. Our roadmap always shaped by you with your feedback.

Share feedback or a request