Add Stripe billing, free trials, and cross-platform subscription guards
- Stripe integration: add StripeService with checkout sessions, customer portal, and webhook handling for subscription lifecycle events. - Free trials: auto-start configurable trial on first subscription check, with admin-controllable duration and enable/disable toggle. - Cross-platform guard: prevent duplicate subscriptions across iOS, Android, and Stripe by checking existing platform before allowing purchase. - Subscription model: add Stripe fields (customer_id, subscription_id, price_id), trial fields (trial_start, trial_end, trial_used), and SubscriptionSource/IsTrialActive helpers. - API: add trial and source fields to status response, update OpenAPI spec. - Clean up stale migration and audit docs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2350,6 +2350,121 @@ paths:
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
/subscription/checkout/:
|
||||
post:
|
||||
tags: [Subscriptions]
|
||||
operationId: createCheckoutSession
|
||||
summary: Create a Stripe Checkout session for web subscription purchase
|
||||
security:
|
||||
- tokenAuth: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [price_id, success_url, cancel_url]
|
||||
properties:
|
||||
price_id:
|
||||
type: string
|
||||
description: Stripe Price ID
|
||||
success_url:
|
||||
type: string
|
||||
format: uri
|
||||
cancel_url:
|
||||
type: string
|
||||
format: uri
|
||||
responses:
|
||||
'200':
|
||||
description: Checkout session created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
checkout_url:
|
||||
type: string
|
||||
format: uri
|
||||
'400':
|
||||
$ref: '#/components/responses/Error'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'409':
|
||||
description: Already subscribed on another platform
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
existing_platform:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
||||
|
||||
/subscription/portal/:
|
||||
post:
|
||||
tags: [Subscriptions]
|
||||
operationId: createPortalSession
|
||||
summary: Create a Stripe Customer Portal session for managing web subscriptions
|
||||
security:
|
||||
- tokenAuth: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [return_url]
|
||||
properties:
|
||||
return_url:
|
||||
type: string
|
||||
format: uri
|
||||
responses:
|
||||
'200':
|
||||
description: Portal session created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
portal_url:
|
||||
type: string
|
||||
format: uri
|
||||
'400':
|
||||
$ref: '#/components/responses/Error'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
/subscription/webhook/stripe/:
|
||||
post:
|
||||
tags: [Subscriptions]
|
||||
operationId: handleStripeWebhook
|
||||
summary: Handle Stripe webhook events (server-to-server)
|
||||
description: |
|
||||
Receives Stripe webhook events for subscription lifecycle management.
|
||||
Verifies the webhook signature using the configured signing secret.
|
||||
No auth token required — uses Stripe signature verification.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
responses:
|
||||
'200':
|
||||
description: Webhook processed successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
received:
|
||||
type: boolean
|
||||
'400':
|
||||
$ref: '#/components/responses/Error'
|
||||
|
||||
# ===========================================================================
|
||||
# Uploads
|
||||
# ===========================================================================
|
||||
@@ -4434,6 +4549,12 @@ components:
|
||||
SubscriptionStatusResponse:
|
||||
type: object
|
||||
properties:
|
||||
tier:
|
||||
type: string
|
||||
description: 'Subscription tier (free or pro)'
|
||||
is_active:
|
||||
type: boolean
|
||||
description: Whether the subscription is currently active
|
||||
subscribed_at:
|
||||
type: string
|
||||
format: date-time
|
||||
@@ -4444,6 +4565,20 @@ components:
|
||||
nullable: true
|
||||
auto_renew:
|
||||
type: boolean
|
||||
trial_start:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
trial_end:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
trial_active:
|
||||
type: boolean
|
||||
subscription_source:
|
||||
type: string
|
||||
nullable: true
|
||||
description: 'Platform source of the active subscription (ios, android, stripe, or null)'
|
||||
usage:
|
||||
$ref: '#/components/schemas/UsageResponse'
|
||||
limits:
|
||||
|
||||
Reference in New Issue
Block a user