Document first_period on subscription.renewed and login-free billing portal links

- subscription.renewed is now sent for the first paid period too;
  data.period.first_period tells it apart (README, EventType, test payload).
- Billing portal links need no login, are single use and valid for about
  15 minutes: create them on click and redirect right away (README,
  createBillingPortalLinkForUser(), appBillingPortalUrl()).
This commit is contained in:
Maurice Preuß committed 2026-11-04 21:57:49 +01:00
1 parent 35ca9ddd2b
commit 7f16155701
6 files changed
+71 -33

No files matched your search

+5 -4
View File
@@ -69,10 +69,11 @@ trait ManagesSubscriptions
}
/**
* A short-lived link to the user's billing pages on Anikeen ID, created with the app's own
* token (trusted apps only, scope subscriptions:client or orders:client), e.g. for a "Manage
* billing" button; see AnikeenId::createBillingPortalLinkForUser() for the attributes
* (return_url, group, flow). Create it when the user clicks, it expires after about 15 minutes.
* A link to the user's billing pages on Anikeen ID that needs no login, created with the app's
* own token (trusted apps only, scope subscriptions:client or orders:client), e.g. for a
* "Manage billing" button; see AnikeenId::createBillingPortalLinkForUser() for the attributes
* (return_url, group, flow). Single use and valid for about 15 minutes: create it when the
* user clicks and redirect right away.
*
* @param array{return_url?: null|string, group?: null|string, flow?: null|string} $attributes
*
+8 -6
View File
@@ -32,12 +32,14 @@ trait ManagesUserBilling
}
/**
* A short-lived link to a user's billing pages on Anikeen ID, e.g. for a "Manage billing"
* button of an app that bills another user's account (a team owner) without that user's
* token (trusted apps, scope subscriptions:client or orders:client). The link is signed and
* valid for about 15 minutes: create it when the user clicks, don't store it. It doesn't sign
* anyone in; the pages then show only what bills the app's subscriptions (of the group) and
* lead back to return_url.
* A link to a user's billing pages on Anikeen ID that needs no login, like Stripe's customer
* portal, e.g. for a "Manage billing" button of an app that bills another user's account (a
* team owner) without that user's token (trusted apps, scope subscriptions:client or
* orders:client). The link is single use and valid for about 15 minutes: create it when the
* user clicks and redirect right away, don't store it. It opens a portal session for that user
* only (no login, nobody signed in) with only the flow's billing pages and only what bills the
* app's subscriptions (of the group), leading back to return_url; it ends after an hour
* without activity.
*
* @param string $userId The user's Anikeen ID.
* @param array{
+4 -2
View File
@@ -34,8 +34,10 @@ final class EventType
public const SUBSCRIPTION_UPDATED = 'subscription.updated';
/**
* A new period of a running subscription was booked on its collective order; `data.period`
* describes it. Opt-in: only endpoints that select this event get it (not through `*`).
* A period of a subscription was booked on its collective order, the first one included;
* `data.period` describes it, `data.period.first_period` is true for the subscription's first
* paid period (checkout or the end of a free trial). Opt-in: only endpoints that select this
* event get it (not through `*`).
*/
public const SUBSCRIPTION_RENEWED = 'subscription.renewed';