Skip to main content
POST
/
apps
/
billing
/
subscribe
App Subscriptions
curl --request POST \
  --url https://api.launchmystore.io/apps/billing/subscribe \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "monthly": 123,
  "yearly": 123,
  "currency": "<string>",
  "appId": "<string>",
  "planInterval": "<string>",
  "successUrl": "<string>",
  "cancelUrl": "<string>",
  "installationId": "<string>"
}
'
{
  "data.subscriptionId": "<string>",
  "data.installationId": "<string>",
  "data.status": "<string>",
  "data.currentPeriodEnd": "<string>",
  "data.url": "<string>",
  "data.sessionId": "<string>",
  "data.cancelAtPeriodEnd": true
}

Documentation Index

Fetch the complete documentation index at: https://docs.launchmystore.io/llms.txt

Use this file to discover all available pages before exploring further.

App subscriptions are the recurring (or one-time) charges a merchant pays for an installed app. They are distinct from the store-level platform subscription at /api/v1/billing/* — each one is scoped to an AppInstallation row that links a single app to a single merchant. A subscription is always created against an existing installation. If the app is not installed yet, the API returns 404 — App is not installed. Auth: merchant JWT (Authorization: Bearer <merchant-jwt>). All endpoints below are gated by @Auth(MERCHANT) — they cannot be called with an OAuth app token.

Charge approval flow

  1. App developer publishes pricing for their app: POST /apps/billing/pricing/:appId with { monthly, yearly, currency }. This provisions the Stripe Product + Price objects.
  2. Merchant installs the app via the marketplace.
  3. App (or merchant UI) calls POST /apps/billing/checkout-session to obtain a Stripe Checkout URL. The merchant is redirected, completes payment, and is returned to successUrl.
  4. Stripe fires checkout.session.completedPOST /apps/billing/webhook verifies the signature and marks the installation as subscribed plus inserts an AppBillingTransactions row.
  5. Subsequent renewals fire invoice.paid webhooks; one transaction row is created per cycle.
For usage-based pricing (per-API-call, per-email-sent, etc.) the developer also records usage events via POST /apps/billing/usage — see Usage Records.

Setup pricing

appId
string
required
Application UUID. The app must be owned by the calling developer or admin.
monthly
number
required
Monthly recurring price in major currency units (e.g. 9.99 for $9.99).
yearly
number
required
Yearly recurring price in major currency units.
currency
string
required
ISO-4217 currency code (e.g. USD, EUR, INR).
curl -X POST "https://api.launchmystore.io/apps/billing/pricing/<APP_ID>" \
  -H "Authorization: Bearer <MERCHANT_JWT>" \
  -H "Content-Type: application/json" \
  -d '{ "monthly": 9.99, "yearly": 99.00, "currency": "USD" }'
Returns { status, type, message, data: { stripeProductId, stripePriceMonthly, stripePriceYearly } }.

Subscribe an installation

POST /apps/billing/subscribe creates a Stripe Subscription wired to the merchant’s stored payment method. Use this when the merchant has already saved a card on the platform; for first-time card collection, use /checkout-session (below).
appId
string
required
Application UUID. Must correspond to an existing AppInstallation row for the calling store; otherwise 404.
planInterval
string
required
Either monthly or yearly. The Stripe Price for that interval must have been provisioned via POST /pricing/:appId.
curl -X POST "https://api.launchmystore.io/apps/billing/subscribe" \
  -H "Authorization: Bearer <MERCHANT_JWT>" \
  -H "Content-Type: application/json" \
  -d '{ "appId": "fb7c…", "planInterval": "monthly" }'
data.subscriptionId
string
Stripe Subscription id.
data.installationId
string
UUID of the AppInstallation now linked to this subscription.
data.status
string
Stripe status: active, incomplete, incomplete_expired, past_due, canceled, trialing, unpaid.
data.currentPeriodEnd
string
ISO timestamp of next renewal.

Hosted checkout session (charge approval URL)

POST /apps/billing/checkout-session returns a Stripe Checkout URL. This is the canonical “charge approval URL” — redirect the merchant to it, they pay, Stripe redirects them back to successUrl.
appId
string
required
UUID of the installed app.
planInterval
string
required
One of monthly, yearly, one_time. one_time is used for non-recurring app charges.
successUrl
string
URL Stripe redirects to on payment success. Defaults to the app’s configured success URL.
cancelUrl
string
URL Stripe redirects to if the merchant abandons checkout. Defaults to the app’s configured cancel URL.
curl -X POST "https://api.launchmystore.io/apps/billing/checkout-session" \
  -H "Authorization: Bearer <MERCHANT_JWT>" \
  -H "Content-Type: application/json" \
  -d '{
    "appId": "fb7c…",
    "planInterval": "monthly",
    "successUrl": "https://app.example.com/billing/return?success=1",
    "cancelUrl":  "https://app.example.com/billing/return?cancel=1"
  }'
data.url
string
Stripe-hosted checkout URL. Open in a new tab or redirect.
data.sessionId
string
cs_… Stripe Checkout Session id.
data.installationId
string
UUID of the linked installation.

Cancel a subscription

POST /apps/billing/cancel cancels the Stripe Subscription tied to an installation. The installation row remains; only the recurring charge is stopped. Cancellation takes effect at the end of the current billing period — the merchant retains access until then.
installationId
string
required
UUID of the AppInstallation. Get it from GET /apps/installations or from the subscribe / checkout-session response.
curl -X POST "https://api.launchmystore.io/apps/billing/cancel" \
  -H "Authorization: Bearer <MERCHANT_JWT>" \
  -H "Content-Type: application/json" \
  -d '{ "installationId": "f73049dc-…" }'
data.status
string
Stripe subscription status after cancellation — typically canceled (if immediate) or active with cancelAtPeriodEnd: true.
data.cancelAtPeriodEnd
boolean
true when the merchant keeps access until currentPeriodEnd.
data.currentPeriodEnd
string
ISO end date.

Active subscriptions for a merchant

There is currently no dedicated “list app subscriptions for this merchant” endpoint. Use one of:
  • GET /apps/installations (merchant) → each row carries billing: { subscriptionId, status, currentPeriodEnd, planInterval }.
  • GET /apps/billing/transactions (merchant) → groups paid invoices per installation. See Transactions.
A dedicated GET /apps/billing/subscriptions endpoint that returns just the active subscription rows for the merchant is planned but not yet exposed publicly.

Webhook

POST /apps/billing/webhook (public, no auth) is the Stripe webhook endpoint. The handler verifies the Stripe-Signature header against STRIPE_APP_BILLING_WEBHOOK_SECRET and processes:
EventEffect
checkout.session.completedActivates the installation, inserts a paid AppBillingTransactions row, fires the app/subscription/created outbound webhook to the app.
invoice.paidInserts a paid transaction row for the renewal cycle.
invoice.payment_failedMarks the installation as past_due; fires app/subscription/past_due.
customer.subscription.deletedMarks the installation as cancelled; fires app/subscription/cancelled.
Apps subscribe to these outbound webhook topics in their manifest — they do NOT receive the raw Stripe webhook.

Error codes

CodeDescription
400Missing Stripe-Signature header or unverifiable signature (webhook only).
400planInterval not one of monthly / yearly / one_time.
401Missing or invalid merchant JWT.
404App is not installed — call POST /apps/install/:appId first.
500Stripe API error (logged with the underlying Stripe error code).