Get billing state
Billing
Get billing state
Returns the user-facing paywall flag, the launch-phase counters, and the caller’s current subscription status.
GET
Get billing state
Overview
Combines two facts into a single read:- The global paywall flag — is the 50-listing launch-phase threshold still active for the platform as a whole? See Paywall and launch phase for the rule and the one-way flip semantics.
- The caller’s subscription status —
ACTIVE,TRIALING,CANCELLED,EXPIRED,PAST_DUE, orNONEwhen the user has never subscribed.
paywallActive === false no purchase prompt is needed; once it flips to true, only users with subscriptionStatus ∈ { ACTIVE, TRIALING } retain access to paywalled features.
The paywall calculator is cached in Redis for 60 seconds (key
paywall:state:v1). Two requests within the same 60s window may return identical currentListings even if the live count just changed. The flip itself is one-way and durable — the cache TTL only affects how quickly clients observe a new flip, not whether the paywall stays on once it has flipped.Authentication
Bearer <accessToken> required. requireAuth middleware applied. requireOnboarded is NOT applied — pre-onboarded users still need to be able to read the paywall flag (e.g. to gate the onboarding CTA itself).
Path parameters
None.Query parameters
None.Request body
None.Response — 200 OK
| Field | Type | Notes | Example |
|---|---|---|---|
paywallActive | boolean | true once the platform has ever crossed the 50-listing threshold. Once true, never goes back to false in the same deployment (one-way flip — see concept page). | false |
reason | enum | launch_phase while paywallActive is still false; after_launch once it has flipped. | launch_phase |
currentListings | integer | Live count of CurrentHome rows where status === 'LIVE' AND ownerTenancyApproved === true. Read through the 60s cache. | 12 |
threshold | integer | The launch-phase threshold. Currently 50 (PAYWALL_THRESHOLD_DEFAULT). | 50 |
subscriptionStatus | enum | ACTIVE, TRIALING, CANCELLED, EXPIRED, PAST_DUE, or NONE if the user has never had a subscription row. Mirrored from the user’s denormalised subscriptionStatus field; the source of truth lives in the subscriptions collection. | NONE |
After the flip + an active subscriber
After the flip + a trial user
Subscription status values
| Value | Meaning | Source RC event |
|---|---|---|
NONE | User has never subscribed (no subscriptions row). | — |
TRIALING | In the 7-day free trial. | INITIAL_PURCHASE with period_type === 'TRIAL' |
ACTIVE | Paid period in effect. | RENEWAL, NON_RENEWING_PURCHASE, PRODUCT_CHANGE, UNCANCELLATION |
CANCELLED | User cancelled but still has access until currentPeriodEnd. | CANCELLATION |
EXPIRED | Period ended; access revoked. | EXPIRATION |
PAST_DUE | Billing failed or RC paused the subscription. | BILLING_ISSUE, SUBSCRIPTION_PAUSED |
Error responses
| Status | Code | Meaning |
|---|---|---|
| 401 | UNAUTHENTICATED | Missing, malformed, or expired access token. |
Example error — 401 UNAUTHENTICATED
See also
- Paywall and launch phase — the rule, the one-way flip, the cache.
- Push notification fan-out — trial-ending pushes (deferred to Phase 7).
- RevenueCat webhook — how subscription status gets updated.
curl
Postman
Seedocs/postman/swappr.postman_collection.json → Billing → Get state.