Stripe Billing
PickLayer’s first-party payment processor is Stripe. End-user subscriptions, payment-method management, overage credits, and webhook-driven renewals all run through Stripe. For the cross-cutting usage and quota model that backs all funding sources, see the billing overview.
For iOS in-app purchases (where Stripe is not permitted), use the Apple App Store integration instead.
Billing API
PickLayer provides end-user billing endpoints for subscription management. All billing routes require an end-user JWT.
List available plans
GET /v1/billing/plans
Returns all billing plans available for the application:
{
"code": 200,
"type": "success",
"data": {
"plans": [
{
"id": "plan-uuid",
"name": "Pro Plan",
"description": "Unlimited access",
"price_cents": 2999,
"currency": "usd",
"interval": "month",
"monthly_cost_cap": 100,
"fundingModes": [
{ "id": "fm-uuid", "type": "USER", "stripePrice": "price_xxx" }
]
}
]
}
}Subscribe to a plan
POST /v1/billing/subscribe
{
"planId": "plan-uuid",
"fundingModeId": "fm-uuid",
"paymentMethodToken": "tok_visa"
}paymentMethodTokenorpaymentMethodIdattaches the card and starts the subscription immediately- On success, creates a Stripe subscription and activates the user’s plan assignment
- Returns subscription details and payment intent info if SCA is required
Check billing readiness
GET /v1/billing/readiness
Returns the user’s current billing status for UI display:
{
"code": 200,
"type": "success",
"data": {
"funded": true,
"percentRemaining": 85.5,
"billingModel": "USER",
"reason": null,
"plan": { "id": "...", "name": "Pro Plan" },
"next_plan": null,
"pending_effective_at": null,
"cancel_at": null,
"renewal_at": "2026-02-20T00:00:00Z",
"subscription": {
"status": "active",
"pending_payment": false
},
"cap_windows": [
{ "type": "monthly", "used_cents": 1450, "cap_cents": 10000, "percent_used": 14.5 }
]
}
}Possible reason values when funded: false:
no_subscription– User has no active subscriptionsubscription_canceled– Subscription was canceledperiod_inactive– Subscription period expired (may auto-sync from Stripe)funding_exhausted– Usage cap reachedpayment_failed– Subscription has failed payment
Get billing status (detailed)
GET /v1/billing/status
Builder/system endpoint with additional wallet and Stripe details. End-users should use /billing/readiness.
Change plan (upgrade/downgrade/cancel)
POST /v1/billing/plan-change
{
"action": "upgrade",
"targetPlanId": "plan-uuid",
"targetFundingModeId": "fm-uuid",
"paymentMethodToken": "tok_visa",
"prorationBehavior": "create_prorations"
}Actions:
upgrade– Switch to a higher-tier plan (immediate)downgrade– Switch to a lower-tier plan (at period end)cancel– Cancel subscription (at period end)reactivate– Undo pending cancellation
Update payment method
POST /v1/billing/payment-method
{
"paymentMethodToken": "tok_visa"
}Replaces the default payment method on the subscription. If the subscription is in past_due or unpaid status (due to a failed renewal payment), automatically attempts to pay the most recent failed invoice with the new payment method. This allows users to fix payment issues in a single call.
Retry failed payment
POST /v1/billing/retry-payment
{}Retries payment for a failed subscription renewal using the default payment method. Use when subscription shows past_due status.
Response:
{
"code": 200,
"type": "success",
"data": {
"invoiceId": "in_xxx",
"status": "paid",
"paymentIntent": { "id": "pi_xxx", "status": "succeeded" }
}
}Returns 400 if no failed invoice exists.
Sync subscription from Stripe
POST /v1/billing/sync-subscription
{}Forces a refresh of the local subscription period from Stripe. Use when the local subscription appears expired but Stripe may have renewed it (e.g., missed webhooks).
Response:
{
"code": 200,
"type": "success",
"data": {
"synced": true,
"subscriptionId": "sub_xxx"
}
}Note: /billing/readiness performs this sync automatically when it detects an expired period.
Overage Credits
Overage credits let users pre-load funds to cover usage beyond their subscription plan’s included allowance. Credits are purchased via Stripe and carry a 10% platform fee at load time.
Load credits
POST /v1/billing/overage-credits/load
{
"amount_cents": 1000,
"use_saved_payment_method": true,
"force_checkout": false,
"success_url": "https://yourapp.com/billing/success",
"cancel_url": "https://yourapp.com/billing/cancel"
}amount_cents: Amount to load, in cents. Range: $5–$500 ($500–$50,000 cents).use_saved_payment_method: Charge the user’s saved card immediately iftrue. Iffalseor no card is saved, a Stripe Checkout session URL is returned.force_checkout: Always redirect to Checkout even if a saved card is present.success_url/cancel_url: Redirect destinations when using Checkout.
A 10% platform fee is applied at load time (e.g., loading $10.00 adds $9.09 of spendable credit).
Get credit balance
GET /v1/billing/overage-credits/balance
{
"overage_credits_pusd": 9.09,
"subscription_credits_pusd": 0,
"total_available_pusd": 9.09,
"overages_enabled": true,
"plan_overage_mode": "credits"
}overage_credits_pusd: Pre-loaded overage credit balance in platform USD.subscription_credits_pusd: Credits rolled over from the subscription plan.total_available_pusd: Combined spendable balance.overages_enabled: Whether the user has opted into overage spending.plan_overage_mode: How the billing plan handles overages (credits,disabled, etc.).
Toggle overage opt-in
POST /v1/billing/overage-credits/settings
{
"overages_enabled": true
}Enables or disables overage spending for the user. When disabled, requests that exceed the subscription allowance return 429 QUOTA regardless of available credit balance.