Billing Service API

Base URL: https://billing.stashly.io

ℹ

Team members cannot access billing

All billing endpoints require JWT authentication and the caller must not be a member role. Only admin and solo users can manage billing.


Plans#

GET/plans

List all publicly available plans.

200Plans
{
  "success": true,
  "data": [
    {
      "id": "plan_free",
      "name": "Free",
      "price": 0,
      "storageGb": 5,
      "features": ["5 GB storage", "API access", "1 bucket"]
    },
    {
      "id": "plan_pro",
      "name": "Pro",
      "price": 2900,
      "storageGb": 100,
      "features": ["100 GB storage", "Unlimited buckets", "Webhooks"]
    }
  ]
}
GET/plans/:id

Get details for a specific plan.


Subscriptions#

POST/billing/checkoutJWT Required

Create a Stripe Checkout session for plan selection. Returns a redirect URL.

Request Body

NameTypeDescription
planId*stringThe plan ID to subscribe to
successUrl*stringURL to redirect after successful payment
cancelUrl*stringURL to redirect if user cancels checkout
200Checkout URL
{
  "success": true,
  "data": { "url": "https://checkout.stripe.com/pay/cs_test_..." }
}
POST/billing/subscribeJWT Required

Subscribe directly to a plan (for plans with a saved payment method).

Request Body

NameTypeDescription
planId*stringThe plan ID to subscribe to
POST/billing/portalJWT Required

Create a Stripe Customer Portal session for managing payment methods, invoices, and subscriptions.

Request Body

NameTypeDescription
returnUrl*stringURL to return to after leaving the portal
200Portal URL
{
  "success": true,
  "data": { "url": "https://billing.stripe.com/p/session/..." }
}
GET/billing/subscriptionJWT Required

Get the user's subscription details.

200Subscription
{
  "success": true,
  "data": {
    "id": "sub_01j9",
    "plan": "pro",
    "status": "active",
    "currentPeriodEnd": "2025-06-29T00:00:00Z",
    "cancelAtPeriodEnd": false
  }
}
GET/billing/currentJWT Required

Get the user's current active subscription (shorthand, returns just the active subscription).

POST/billing/cancelJWT Required

Cancel the current subscription. It remains active until the end of the billing period.

200Cancelled
{
  "success": true,
  "data": { "cancelAtPeriodEnd": true, "currentPeriodEnd": "2025-06-29T00:00:00Z" }
}
POST/billing/update-planJWT Required

Upgrade or downgrade the subscription plan. Takes effect immediately (prorated).

Request Body

NameTypeDescription
planId*stringThe new plan ID
POST/billing/apply-couponJWT Required

Apply a discount coupon to the current subscription.

Request Body

NameTypeDescription
code*stringCoupon code to apply
200Coupon applied
{
  "success": true,
  "data": { "discount": 20, "type": "percent", "validUntil": "2025-12-31T00:00:00Z" }
}
400Invalid coupon
{ "success": false, "message": "Coupon code is invalid or expired" }

Webhooks#

POST/webhooks/stripe

Stripe webhook receiver. Requires Stripe-Signature header verification. Must receive raw body.

See the Webhooks guide for full details on signature verification and event handling.