---
title: "Upgrade or downgrade to another plan (dashboard session required)"
method: POST
path: "/v1/subscription/plan"
---

# Upgrade or downgrade to another plan (dashboard session required)

`POST /v1/subscription/plan`

## Request

- Base URL: `https://agentmandate-api.com`
- URL: `https://agentmandate-api.com/v1/subscription/plan`
- Auth: API key in cookie `sp_session` and API key in header `x-csrf-token`

Moves this account to another rung of the published pricing ladder and re-derives the ceiling enforced against every API key on it, so an upgrade is usable immediately rather than at the next invoice. The change is STAGED, not overwritten: the current billing window is closed at this instant and priced against the tier that was actually in force for it, and the incoming tier opens the next window with the original billing anniversary preserved. A downgrade therefore never re-prices days you already consumed on the dearer plan. Refused with 409 `conflict` (`details.reason` `provider_owned_base_fee`) when Square’s own recurring subscription holds your price (`baseFeeOwner` is `provider`) — read `planChangesGoThrough` from GET /v1/subscription first. That case cannot be moved from here at all: this API holds no Square subscription of yours to change, and POST /v1/checkout would create a SECOND one and charge you for both. Cancel with Square and buy the tier you want, or contact support. AUTHENTICATION IS YOUR DASHBOARD SESSION, NOT AN API KEY. Send the `@sp/core` session cookie this API sets when you sign in, from the same origin. An API key is refused here on purpose: it is a data-plane credential that lives in CI and in third-party integrations, and it must never be able to change what you are billed, cancel your account, or read your payment history. Errors: 401 `unauthenticated` when there is no valid session, 403 `forbidden` when the request is cross-origin or its `x-csrf-token` header is missing or wrong.

## Request body

- object
  - `planId` string, required: Tier id from GET /v1/subscription `tiers[].id`, e.g. "growth".

## Response `200`

Success

- object
  - `changed` boolean
  - `direction` 'upgrade' | 'downgrade'
  - `from` string
  - `to` string
  - `entitlement` object: The ceiling now enforced on this account’s keys, and when it took effect.
  - `billing` object: Which tier the closed window is priced against, and when the new one starts.
  - `requestId` string

## Other responses

- `400`: Deterministic error. Branch on `code`; quote `requestId` when reporting a problem.
- `401`: Deterministic error. Branch on `code`; quote `requestId` when reporting a problem.
- `403`: Deterministic error. Branch on `code`; quote `requestId` when reporting a problem.
- `409`: Deterministic error. Branch on `code`; quote `requestId` when reporting a problem.
- `500`: Deterministic error. Branch on `code`; quote `requestId` when reporting a problem.

---

[API](https://skmtc.dev/agentmandate-api/apis/agent-mandate.md) · [All operations](https://skmtc.dev/agentmandate-api/apis/agent-mandate/llms.txt) · [OpenAPI document](https://skmtc.dev/agentmandate-api/apis/agent-mandate/revisions/463fe122c4d8?raw)
