subscription

Checkout Complete

Settle state after a successful Stripe checkout, then return the status.

Stamps a short grace snooze (so a status read in the redirect→webhook window doesn't bounce a fresh payer to /paywall) and optimistically sets the store to STRIPE, then returns the freshly-settled status from the same projection GET /status uses - so the post-checkout caller keeps its single round-trip.

The grace is gated on RevenueCat - the entitlement broker that ingests Stripe and feeds our /webhooks/revenuecat handler - confirming the caller's own entitlement (keyed on the JWT user id, so nothing here is forgeable). Without that gate any authenticated free account could POST here on a loop to self-grant a permanent paywall snooze, bypassing even the hard lockout (#4623):

  • RevenueCat confirms an active entitlement → stamp the grace (verified).
  • RevenueCat unreachable → stamp it anyway, logged loudly, so an RC outage never re-paywalls a real payer. Bounded to CHECKOUT_GRACE_MINUTES; the webhook reconciles authoritatively.
  • RevenueCat reachable but no active entitlement → the self-grant case. Behaviour here depends on CHECKOUT_GRACE_ENFORCE_REVENUECAT:

Two-phase rollout. The gate ships in observe mode by default: the RevenueCat lookup runs and every would-be denial is logged, but the grace is still stamped - so the deploy changes nothing a returning payer sees and cannot regress the redirect→webhook bridge. The logs measure the real false-negative rate (genuine payers still inside RC's Stripe-ingestion lag) in prod. Flip CHECKOUT_GRACE_ENFORCE_REVENUECAT=true to enforce - then a no-entitlement caller gets no grace, closing the self-grant. The flip is a config change, not a deploy, and instantly reversible. Even under enforcement the blast radius is one CHECKOUT_GRACE_MINUTES window for a fresh payer, cleared by the webhook within minutes.

Re-POSTing just re-stamps the same window (idempotent).

post/subscription/checkout-complete

Request

  • Base URL
    https://api.projectindi.com (the document declares no server; this is the origin it was published from)
  • Auth
    none declared

Response

Successful Response

subscription_statusstring required
subscription_storestring nullable required
has_active_subscriptionboolean required
subscription_expires_atstring nullable required
is_billing_contactboolean required
is_locked_outboolean required
trial_expiredboolean required
message_countinteger required
requires_paymentboolean required
is_snoozedboolean
snoozed_untilstring nullable
is_clinic_referredboolean
clinic_namestring nullable
is_sponsoredboolean
sponsoring_clinic_namestring nullable
sponsorship_ends_atstring nullable
has_own_subscriptionboolean
trial_eligibleboolean required
jurisdiction_codestring nullable
has_pending_ndis_requestboolean
plan_typestring nullable
prefill_clinicianstring nullable
pending_user_action_storestring nullable
pending_user_action_deep_linkstring nullable

Changes

No recorded changes to this operation across all 2 revisions of this API.