Skip to content

Change plan

POST
/orgs/{org}/billing/plan
curl --request POST \
--url https://api.sloose.com/orgs/org_9f3c/billing/plan \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "planKey": "example", "interval": "example", "previewToken": "example" }'

Makes the change POST …/plan/preview describes, for an org with a Stripe subscription. A higher plan is charged now, prorated, and refused whole when the card is (402 CARD_DECLINED): it either is paid for or did not happen, and it lands on the org when Stripe’s webhook says so — usually within a minute, since a delivery made while the change holds the org is retried by Stripe. A lower plan is a Stripe subscription schedule from the period’s end, recorded at once and taken back with DELETE …/plan/pending until then. Free is a cancellation at the period’s end, taken back the same way. A change replaces whatever was waiting: an upgrade takes back a move down, a move down takes back a cancellation.

Who asked is written on the subscription, so the org’s history says it was them and not Stripe. Administrators, through their own session; never a staff member’s view.

org
required

The org id the session was issued for. A token for one org can never read another.

string
Example
org_9f3c

The org id the session was issued for. A token for one org can never read another.

Media typeapplication/json
object
planKey

The plan to move to: team, business or enterprise, or free for a cancellation at the period’s end.

string
interval

month or year, for a paid plan. Defaults to month.

string
previewToken

The token of the preview the person confirmed (#1482 review): the change is held to the terms it priced — the subscription as read, the change, and the moment its proration was priced at — and refused PREVIEW_STALE when they no longer hold. Without one, the change is priced as it is made.

key
additional properties
Examplegenerated
{
"planKey": "example",
"interval": "example",
"previewToken": "example"
}

What was done, and when it lands.

Media typeapplication/json
object
change
required

now: a higher plan (or a year in place of a month), charged now with proration. at_renewal: a lower plan (or a month in place of a year), from the period’s end, which can be taken back until then. cancel: Free, the subscription ending at the period’s end.

string
Allowed values: now at_renewal cancel
effectiveAt
required
string
Example
{
"change": "now"
}

The plan key is not one we sell, or the interval is neither month nor year.

Media typeapplication/json
object
error
required
string
key
additional properties
Examplegenerated
{
"error": "example"
}

No bearer, or one that is expired, revoked or no longer resolves to a member.

Media typeapplication/json

The error envelope every non-2xx answer uses.

object
error
required

Human-readable explanation.

string
code

Machine-readable reason. Absent on a few legacy 400s.

string
key
additional properties
Examplegenerated
{
"error": "example",
"code": "example"
}

An upgrade’s card was declined: nothing changed.

Media typeapplication/json
object
error
required
string
code
required
string
Allowed values: CARD_DECLINED
key
additional properties
Example
{
"code": "CARD_DECLINED"
}

The bearer’s role is too low, it was issued for a different org, it is an API token (SESSION_REQUIRED), or it is a staff member’s view (IMPERSONATION_REFUSED): a change of plan spends the org’s money.

Media typeapplication/json

The error envelope every non-2xx answer uses.

object
error
required

Human-readable explanation.

string
code

Machine-readable reason. Absent on a few legacy 400s.

string
key
additional properties
Examplegenerated
{
"error": "example",
"code": "example"
}

As the preview’s 409, and four more. PREVIEW_STALE: the change was sent with a preview’s token, and the subscription, the change or the moment its proration was priced at no longer hold — or half an hour has passed; nothing was changed, so preview it again. CHANGE_IN_PROGRESS: another change to the org’s plan, or a webhook about it, is being made at this moment; nothing was asked of Stripe. CHANGE_INCOMPLETE: Stripe refused the change, and putting back what it replaced — a move waiting at the renewal, or a cancellation — failed, so it is no longer waiting; reload to see the plan as it stands. CHANGE_UNCONFIRMED: Stripe did not answer, so the change may have been made, and nothing was put back over it; the plan as it stands arrives within a minute, so do not try again yet. error says which, in words to show.

Media typeapplication/json
object
error
required
string
code
required
string
Allowed values: NOT_SUBSCRIBED INVOICE_BILLED NO_CHANGE NOT_CHANGEABLE PLAN_SETTLING CHANGE_IN_PROGRESS CHANGE_INCOMPLETE CHANGE_UNCONFIRMED PREVIEW_STALE
key
additional properties
Example
{
"code": "NOT_SUBSCRIBED"
}

Stripe refused the request (PAYMENT_PROVIDER_REFUSED) — nothing was charged, though a step taken before the refusal stands: the org’s first Stripe customer, or an existing customer’s billing email brought up to date — or was unavailable (PAYMENT_PROVIDER_UNAVAILABLE: unreachable, failing or rate-limiting), which may or may not have gone through — check before retrying. Stripe’s own words are logged, not returned.

Media typeapplication/json
object
error
required
string
code
required
string
Allowed values: PAYMENT_PROVIDER_REFUSED PAYMENT_PROVIDER_UNAVAILABLE
key
additional properties
Example
{
"code": "PAYMENT_PROVIDER_REFUSED"
}

Stripe, or the plan’s price, is not configured.

Media typeapplication/json
object
error
required
string
key
additional properties
Examplegenerated
{
"error": "example"
}

Report a problem with this page