FurniOpsDocs
API referenceBilling

Subscribe, or change plan

Without a subscription, starts one on the plan and interval, with tax from the address and the promotion code's discount, renewing on the 1st (UTC) with the first, partial period prorated; usage past what the plan includes is billed monthly. It answers the payment the browser confirms with Stripe's Payment Element. With one, moves it to the plan with proration; a payment due now is confirmed the same way, and the plan changes only once it succeeds. A move to a lower tier (even monthly to annual), or annual to monthly on the same plan, waits for the end of the term (subscription.scheduled_change) and charges nothing today. The plan itself changes when Stripe confirms, within seconds. While billing is switched off, it answers 409 conflict.

POST/v1/billing/subscription

Without a subscription, starts one on the plan and interval, with tax from the address and the promotion code's discount, renewing on the 1st (UTC) with the first, partial period prorated; usage past what the plan includes is billed monthly. It answers the payment the browser confirms with Stripe's Payment Element. With one, moves it to the plan with proration; a payment due now is confirmed the same way, and the plan changes only once it succeeds. A move to a lower tier (even monthly to annual), or annual to monthly on the same plan, waits for the end of the term (subscription.scheduled_change) and charges nothing today. The plan itself changes when Stripe confirms, within seconds. While billing is switched off, it answers 409 conflict.

Authorization

apiKey
AuthorizationBearer <token>

An API key (fo_live_… / fo_test_…) as a bearer token

In: header

Header Parameters

FurniOps-Version?string

Dated API version; pinned per organisation on first use and overridable per request

Value in

  • "2026-10-01"
  • "2026-10-04"
FurniOps-Mode?string

The data the request acts on: test is the organisation's sandbox. An OAuth token picks it (live by default); an API key's mode is fixed, and naming the other one is refused

Value in

  • "live"
  • "test"
Idempotency-Key*string

Unique key for this operation, reused on retries (24 h)

Length1 <= length <= 257
FurniOps-Dry-Run?string

This operation cannot be previewed (Stripe acts at once; price a plan with previewSubscription): 422 preview_unsupported, nothing changes

Value in

  • "true"
  • "explain"

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

The plan and interval to subscribe to, or to move to

Response Body

application/json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

curl -X POST "https://example.com/v1/billing/subscription" \  -H "Idempotency-Key: string" \  -H "Content-Type: application/json" \  -d '{    "plan": "string"  }'
{  "object": "billing_confirmation",  "kind": "payment",  "client_secret": "string",  "subscription": {    "status": "incomplete",    "plan": "string",    "current_period_end": "2019-08-24T14:15:22Z",    "cancel_at_period_end": true,    "interval": "month",    "cancel_at": "2019-08-24T14:15:22Z",    "discount": {      "name": "string",      "percent_off": 1,      "amount_off": 0,      "ends_at": "2019-08-24T14:15:22Z"    },    "scheduled_change": {      "plan": "string",      "interval": "month",      "effective_at": "2019-08-24T14:15:22Z"    }  }}