Skip to content

Cancel Subscription

POST
/api/billing/cancel

Cancel one product’s subscription for this organization.

Per-product, not per-org: à la carte means an org can hold four independent subscriptions (§12), so cancelling monitoring must not touch OTA. The row is found via the "plan_code:organization_id" composite in subscriptions.product_code — built here from PLAN_CODE_FOR_PRODUCT, the same mapping entitlement_projection._resolve_org_and_product parses that column back out with.

The gateway is called before any local write, so a refusal leaves no record of a cancellation that did not happen. The reverse gap — gateway cancelled, local commit lost — is self-healing: the gateway’s own customer.subscription.deleted webhook re-projects the same absolute state.

Authorizations

Parameters

Query Parameters

organization_id
required
string format: uuid

Request Body required

POST /api/billing/cancel.

product is the à la carte product whose subscription to cancel (‘ota’ | ‘monitoring’ | ‘crash_reporting’ | ‘remote_ssh’) — NOT the subscriptions.product_code column, which is the composite “plan_code:organization_id” (§3.1). Naming it product keeps it in the same vocabulary as organization_entitlements.product and ProductEntitlementItem above; the route resolves the plan_code and the composite from it.

object
at_period_end
boolean
default: true
product
required
string

Responses

200

Successful Response

POST /api/billing/cancel.

object
effective_at
Any of:
string format: date-time
status
required
string

422

Validation Error

object
detail
Array<object>
object
loc
required
Array
msg
required
string
type
required
string