Project information
This reference covers paginated project listing and reading or updating a specific project.
Authentication and permissions
Send an authorized session or organization API Key together with the organization context. The list contains only projects the credential may read. Reading one project requires project.read on project:<project-id>. For updates on this page, also use project.name.update, project.description.update, or project.domain.update, depending on the operation.
List projects
GET /v1/projectQuery parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | List page; must be at least 1 |
limit | integer | 15 | Items per page, from 1 to 50 |
type | string | — | http, postgresql, mariadb, valkey, clickhouse, or job |
profile | string | — | Valkey profile: key_value, cache, or queue; accepted only with type=valkey |
status | string | — | creating, running, resuming, stopped, downloading, failed, failing, or deploying |
search | string | — | Search by name or description (1 to 256 characters) |
sort_by | string | updated_at | updated_at or created_at |
sort_order | string | desc | asc or desc |
Filters can be combined. To list only Valkey caches, for example:
curl "https://api.zenifra.com/v1/project?type=valkey&profile=cache&page=1&limit=15" \
-H "x-api-key: <organization-api-key>" \
-H "x-organization-id: <organization-id>"Reduced response
{
"status": "success",
"message": "get projects with success",
"data": {
"projects": [
{
"id": "<project-id>",
"name": "api-cache",
"type_project": "valkey",
"plan": "cache-free",
"status": "running",
"managed_service": { "profile": "cache" }
}
],
"pagination": { "page": 1, "limit": 15, "total": 1, "pages": 1 }
}
}Rate limit: 100 requests per minute.
The API returns 400 when profile is not key_value, cache, or queue, or when it is sent without type=valkey.
Get project information
Returns the current project state, including status, plan, domain, instances, storage, port, public deployment settings, and type-specific additional information.
GET /v1/project/:idRate limit: 100 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 | Conditional | Required only for PATCH calls |
Response
The example below is reduced to highlight the most commonly used fields. The response may also include fields such as github, image, last_deployment, renew_automatic_contract, custom_domains, network_access, build_failure, updated_at, and created_at.
For HTTP projects, exposure indicates whether the application has a public route (public) or runs without a public domain (private). Private projects may return an empty or absent domain.
{
"status": "success",
"message": "get deployment with success",
"data": {
"name": "my-project",
"description": "My web application",
"domain": "my-project.clients.zenifra.com",
"plan": "basic",
"status": "running",
"type_project": "http",
"exposure": "public",
"instances": 2,
"storage": {
"persistent": false,
"capacity": 1
},
"payment_mode": "hourly",
"port": 3000,
"additional_info": {
"current_instances": 2,
"max_cpu": "500m",
"max_memory": "512Mi"
}
}
}Plan change on Analytics projects
On Analytics projects, GET /v1/project/:id includes plan_change while a plan change is running (in_progress) or after a change that could not be completed (failed). The failed state stays present until the next plan change is accepted, which clears it. The field is absent only when no change is running and no previous failure is recorded.
{ "plan_change": { "status": "in_progress", "to_plan": "analytics-starter", "started_at": "2026-10-11T12:00:00.000Z" } }{ "plan_change": { "status": "failed", "from_plan": "analytics-production", "to_plan": "analytics-starter", "finished_at": "2026-10-11T12:08:00.000Z" } }in_progress means the change continues in the background; check again in a few minutes. failed means the change could not be completed and the project stays on the previous plan (from_plan). See Change plan for the 202 and errors of PATCH /v1/project/:id/plan.
Update Project Exposure
Changes whether an HTTP project exposes a public route.
PATCH /v1/project/:id/exposureAccepts a user session or an organization API Key. Requires project.domain.update.
Body
| Field | Type | Required | Description |
|---|---|---|---|
exposure | string | Yes | Use public to create a public route/domain or private to remove public exposure |
{
"exposure": "private"
}Private projects do not receive a Zenifra subdomain and cannot configure a public domain while they remain private. Only HTTP projects accept this operation.
Response
{
"status": "success",
"message": "project exposure updated with success",
"exposure": "private",
"domain": "",
"custom_domains": []
}When changing to private, the API removes the public route, default subdomain, and custom domains. When changing to public, the API provisions the public route again and returns the available domain.
Errors
| Status | When it happens |
|---|---|
400 | The project is a database (cant change database exposure) |
404 | Project not found |
409 | An exposure change is already in progress for the project, or the requested domain is not available |
503 | A public address could not be assigned right now; try again shortly |
Rate limit: 5 requests every 5 minutes.
Update Project Name
Changes the project name.
PATCH /v1/project/:id/nameRate limit: 10 requests per minute (counted per source IP).
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Project ID |
Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | New project name (minimum 6 characters, maximum 32, lowercase letters and numbers only, hyphens allowed) |
Example
{
"name": "my-new-project"
}Response
{
"status": "success",
"message": "updated with success"
}Update Project Description
Changes the project description.
PATCH /v1/project/:id/descriptionRate limit: 10 requests per minute (counted per source IP).
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Project ID |
Body
| Field | Type | Required | Description |
|---|---|---|---|
description | string | No | New project description (1 to 256 characters) |
Response
{
"status": "success",
"message": "updated with success"
}Examples
Update Name
curl -X PATCH "https://api.zenifra.com/v1/project/507f1f77bcf86cd799439011/name" \
-H "x-api-key: your-api-key" \
-H "x-organization-id: your-organization-id" \
-H "Content-Type: application/json" \
-d '{"name": "my-new-project"}'Update Description
curl -X PATCH "https://api.zenifra.com/v1/project/507f1f77bcf86cd799439011/description" \
-H "x-api-key: your-api-key" \
-H "x-organization-id: your-organization-id" \
-H "Content-Type: application/json" \
-d '{"description": "My web application in production"}'Python
import requests
API_KEY = "your-api-key"
ORGANIZATION_ID = "your-organization-id"
PROJECT_ID = "507f1f77bcf86cd799439011"
headers = {"x-api-key": API_KEY, "x-organization-id": ORGANIZATION_ID}
# Get information
project = requests.get(
f"https://api.zenifra.com/v1/project/{PROJECT_ID}",
headers=headers
).json()
print(project)
# Update name
requests.patch(
f"https://api.zenifra.com/v1/project/{PROJECT_ID}/name",
headers=headers,
json={"name": "my-new-project"}
)
# Update description
requests.patch(
f"https://api.zenifra.com/v1/project/{PROJECT_ID}/description",
headers=headers,
json={"description": "My web application in production"}
)Last updated on