Chainwalk/Documentation
CatalogPlans API

Plans API

Plans belong to a project and are exposed through admin, integration, and public read-only surfaces depending on the operation.

Read plans

bash
GET /v1/admin/tenants/{tenant}/projects/{project_id}/plans?include_draft=true
Authorization: Bearer $JWT
bash
GET /v1/integration/tenants/{tenant}/projects/{project_id}/plans/{id}
X-API-Key: $API_KEY
bash
GET /v1/public/tenants/{tenant}/plans/{id}

Create a plan

bash
POST /v1/admin/tenants/{tenant}/plans
Authorization: Bearer $JWT
Content-Type: application/json

{
  "id": "pro_30",
  "project_id": "default",
  "tier": 1,
  "name": "Pro 30 days",
  "duration_days": 30,
  "grace_days": 3,
  "price": { "amount": 9900000, "currency": "USDT" },
  "fail_open": false,
  "sbt": false
}

Update a plan

bash
PUT /v1/admin/tenants/{tenant}/plans/pro_30
Authorization: Bearer $JWT
Content-Type: application/json

{
  "project_id": "default",
  "tier": 2,
  "name": "Pro 30 days",
  "duration_days": 30,
  "grace_days": 0,
  "price": { "amount": 14900000, "currency": "USDT" },
  "fail_open": false,
  "sbt": false
}

Activate a plan

bash
POST /v1/admin/tenants/{tenant}/plans/pro_30/status
Authorization: Bearer $JWT
Content-Type: application/json

{ "status": "active" }
Info
Canonical ownership is project -> plan, the same way tickets are owned by events. Use project-scoped routes as the primary mental model and UI path. The current admin runtime still accepts top-level plan mutations for compatibility, but the authoritative parent is the project via project_id. The current backend also normalizes the active wire status to published in the frontend UI, while the API surface still accepts active.

Upload plan metadata

bash
POST /v1/admin/tenants/{tenant}/plans/pro_30/metadata
Authorization: Bearer $JWT
Content-Type: multipart/form-data

image=@plan.png
description=Pro tier
attributes=[{"trait_type":"tier","value":"pro"}]