---
title: "Set Tenant Plan"
method: POST
path: "/api/admin/tenants/{tenant_id}/plan"
tags: ["admin"]
---

# Set Tenant Plan

`POST /api/admin/tenants/{tenant_id}/plan`

## Request

- Base URL: `https://api.advisorppc.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.advisorppc.com/api/admin/tenants/{tenant_id}/plan`
- Auth: HTTP bearer

Grant or revoke a tenant's entitlement without going through Stripe.

Refuses outright when Stripe owns the row. That is the one case where
overriding here would put the product and the payment processor into
disagreement about what a customer bought — change it in Stripe and let the
webhook land. Everything written here is ``billing_source='manual'`` with
NULL Stripe ids, which the database enforces and the webhook receiver knows
how to conflict on.

## Path parameters

- `tenant_id` integer, required

## Headers

- `X-Tenant-Id` integer, nullable

## Request body

- PlanGrantIn: A deliberate, attributed plan change. ``reason`` is not optional.
  - `tier` 'free' | 'pro' | 'google' | 'gm' | 'gmt' | 'max' | 'agency' | 'team' | 'enterprise', required
  - `status` 'active' | 'inactive' | 'canceled'
  - `reason` string, required

## Response `200`

Successful Response

- TenantPlanRow: One tenant's entitlement as an operator needs to see it.
  - `tenantId` string, required
  - `name` string, required
  - `tier` string, required
  - `status` string, required
  - `billingSource` string, required
  - `members` integer, required
  - `updatedAt` string, nullable
  - `editable` boolean, required

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/advisorppc/apis/advisorppc-api.md) · [All operations](https://skmtc.dev/advisorppc/apis/advisorppc-api/llms.txt) · [OpenAPI document](https://skmtc.dev/advisorppc/apis/advisorppc-api/revisions/3441bd729e0c?raw)
