Update Project Plan
Changes the project to a new plan.
Required permissions
Changing the plan requires project.plan.update on project:<project-id>. owner has full access; assistant, member, and organization API Keys need this grant. If the plan change involves billing data, also use project.billing.read when automation needs to read costs.
PATCH /v1/project/:id/planRate limit: 5 requests per minute (counted per source IP).
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Project ID |
Headers
| Header | Required | Description |
|---|---|---|
x-api-key or Authorization | Yes | Organization API Key or user token |
x-organization-id | With a user token | Active project organization. Not needed with an organization API key |
Content-Type: application/json | Yes | Required because the request has a JSON body |
Body
| Field | Type | Required | Description |
|---|---|---|---|
plan | string | Yes | Plan identifier |
Available Plans
| Plan | Description |
|---|---|
static | Static plan |
basic | Basic plan |
premium | Premium plan |
premium_plus | Premium plus plan |
business | Business plan |
deep_learning_basic | Basic Deep Learning (with GPU) |
deep_learning_premium | Premium Deep Learning (with GPU) |
db-starter, db-basic, db-premium, db-enterprise | Database and Key-Value plans |
The free and db-free plans and the Cache and Queue plans are not accepted on this route. Analytics projects accept analytics-* plans (analytics-sandbox, analytics-starter, analytics-production, analytics-enterprise), both upgrading and downgrading; the plan defines the instances (1 on Sandbox and Starter, 3 on Production and Enterprise). For Key-Value projects, the change is only accepted between plans with the same number of instances and the same billed storage; otherwise the API responds 409.
Example
{
"plan": "premium"
}Response
{
"status": "success",
"message": "updated with success"
}On Analytics projects, the 200 response above means the change is done. If the change continues in the background, the response is 202:
{
"status": "accepted",
"code": "PLAN_CHANGE_IN_PROGRESS",
"message": "The plan change has started and should finish in a few minutes."
}Follow it with GET /v1/project/:id (Project information). When downgrading to a one-instance plan, Zenifra confirms the remaining instance has all the data before removing the others. Billing changes when the change completes.
Errors
| Status | When it happens |
|---|---|
400 | Invalid body (for example, plan missing, free, db-free, or not in the accepted list) |
404 | Project not found, plan does not exist, or the project already has the requested plan (the project already setted with this plan) |
409 | The project is on the free or db-free plan; the project has a monthly or annual contract (cant change plan with contract); the project is a scheduled Job, which does not accept plan changes; there is no capacity available on the new plan (INSUFFICIENT_PLAN_CAPACITY); another operation is in progress on the project (PROJECT_OPERATION_IN_PROGRESS); or, on Analytics, CLICKHOUSE_NON_REPLICATED_DATA (message: "Some tables use an engine without replication and hold data. Move that data to replicated tables before changing to a plan with one instance.") or CLICKHOUSE_REPLICAS_NOT_IN_SYNC (message: "The instances are still synchronizing data. Try the plan change again in a few minutes."). For the first, move the data to tables with the default engine; for the second, try again in a few minutes |
503 | Plan capacity is temporarily unavailable (PLAN_CAPACITY_TEMPORARILY_UNAVAILABLE); try again shortly |
Automatic contract renewal
Turns automatic renewal on or off for a project with a monthly or annual contract.
PATCH /v1/project/:id/renew-automatic-contractAccepts a user session or an organization API Key and requires project.plan.update on project:<project-id>. Rate limit: 5 requests per minute (counted per source IP).
Body
| Field | Type | Required | Description |
|---|---|---|---|
renew_automatic_contract | boolean | Yes | true to renew automatically at the end of the contract; false to not renew |
{
"renew_automatic_contract": false
}Response
{
"status": "success",
"message": "renew automatic contract updated with success"
}Errors
| Status | When it happens |
|---|---|
400 | Invalid body, or the project uses hourly billing, which has no contract renewal |
404 | Project not found |
Examples
curl -X PATCH "https://api.zenifra.com/v1/project/507f1f77bcf86cd799439011/plan" \
-H "x-api-key: your-api-key" \
-H "x-organization-id: your-organization-id" \
-H "Content-Type: application/json" \
-d '{"plan": "premium"}'Python
import requests
API_KEY = "your-api-key"
ORGANIZATION_ID = "your-organization-id"
PROJECT_ID = "507f1f77bcf86cd799439011"
response = requests.patch(
f"https://api.zenifra.com/v1/project/{PROJECT_ID}/plan",
headers={"x-api-key": API_KEY, "x-organization-id": ORGANIZATION_ID},
json={"plan": "premium"}
)
print(response.json())Notes
- Plan change may take a few minutes to be applied
- Plan changes are only accepted for projects with hourly billing; billing uses the new plan price from the change onward
- When you move to a plan without auto-scaling or health check, those features are turned off automatically
- GPU plans (
deep_learning_basic,deep_learning_premium) have their own prices; seeGET /v1/project/plans
Last updated on