Projects API
A project is a deployable unit of code. Its slug is either static (served from Firebase/CDN) or container (run on Kubernetes); when you create with auto, PandaStack detects which one your repo is and resolves the slug for you. Secret values are never returned by the project endpoints below — the env array carries only plaintext variables. Secret names come from a dedicated endpoint, and a value requires an explicit per-secret reveal.
For the conceptual guides see Projects overview, Static sites, Container apps, Environment variables & secrets, Custom domains, and Redirects, rewrites & headers.
All routes below are org-scoped and require authentication. The role floor is noted per endpoint.
The project object
Section titled “The project object”ProjectDetail (returned by get / create-result-adjacent reads):
| Field | Type | Notes |
|---|---|---|
id | number | |
name | string | null | Subdomain-safe name. |
slug | static | container | string | null | Deployment target. |
branch | string | null | Tracked branch. |
repositoryName | string | null | owner/repo. |
organizationId | string | BIGINT serialized as string. |
projectUrl | string | null | Live URL. |
enabled | boolean | Whether the project is active (see toggle). |
isPublic | boolean | |
language | string | null | e.g. nodejs, python, go, docker. |
runtime | string | null | |
region | string | null | |
baseDir | string | null | Build root directory. |
buildDir | string | null | Static output directory. |
buildCmd | string | null | |
startCmd | string | null | Container start command. |
healthCheckPath | string | null | |
dockerFilePath | string | null | |
tier | object | null | Instance tier. |
disk | number | null | Persistent disk (GB). |
autoScaling | object | null | { enabled, minReplicas, maxReplicas, targetCpuPercent }. |
enableAnalytics | boolean | |
autoDeploy | boolean | Deploy on push. |
env | EnvVar[] | { name, value }; secrets excluded. |
totalDeployments | number | |
successDeployments | number | |
failedDeployments | number | |
latestDeployment | object | null | { status, commitId, createdAt }. |
createdAt / updatedAt | string | null |
ProjectListItem (returned in lists) is a compact subset: id, name, slug, branch, repositoryName, organizationId, projectUrl, enabled, latestDeployment, updatedAt.
List projects
Section titled “List projects”GET /v1/projects
Cursor-paginated list of projects in the active org. Secret values are never returned.
Auth: any member.
Query params (ProjectListQuery):
| Param | Type | Required | Notes |
|---|---|---|---|
cursor | string | no | Opaque cursor from a prior nextCursor. |
limit | int | no | 1–100, default 50. |
slug | string | no | Filter by static or container. |
curl "https://api.pandastack.io/v1/projects?limit=20&slug=container" \ -H "Authorization: Bearer $PANDASTACK_TOKEN"{ "success": true, "data": { "items": [ { "id": 812, "name": "marketing-site", "slug": "static", "branch": "main", "repositoryName": "acme/marketing", "organizationId": "1907", "projectUrl": "https://marketing-site.pandastack.app", "enabled": true, "latestDeployment": { "status": "succeeded", "commitId": "a1b2c3d", "createdAt": "2026-07-14T10:00:00Z" }, "updatedAt": "2026-07-14T10:00:12Z" } ], "nextCursor": null }}Create a project
Section titled “Create a project”POST /v1/projects
Creates a project and triggers its first deploy. Static projects deploy fully; container projects need DNS and deploy asynchronously. A source scan runs at build time. The request body is a discriminated union on slug — pick static, container, or auto.
Auth: member.
slug: "static" — CreateStaticInput
Section titled “slug: "static" — CreateStaticInput”| Field | Type | Required | Notes |
|---|---|---|---|
slug | "static" | yes | Discriminator. |
name | string | yes | RFC-1123 label: lowercase letters, numbers, hyphens; 1–63 chars. |
repositoryName | string | yes | owner/repo. |
branch | string | no | Default main. |
baseDir | string | no | Default ./. |
buildDir | string | no | Default dist. |
buildCmd | string | no | Default npm run build. |
autoDeploy | boolean | no | Default false. |
prPreview | boolean | no | Default false. |
isPublic | boolean | no | Default true. |
enableAnalytics | boolean | no | Default false. |
env | EnvVar[] | no | Default []. |
secrets | EnvVar[] | no | Default []; stored base64. Values are never returned by this endpoint. |
slug: "container" — CreateContainerInput
Section titled “slug: "container" — CreateContainerInput”| Field | Type | Required | Notes |
|---|---|---|---|
slug | "container" | yes | Discriminator. |
name | string | yes | RFC-1123 label. |
repositoryName | string | yes | owner/repo. |
branch | string | no | Default main. |
region | string | no | Default us. |
language | enum | yes | auto | nodejs | python | go | docker. |
isPublic | boolean | no | Default true. |
baseDir | string | no | Default ./. |
buildCmd | string | no | Default "". |
startCmd | string | no | Default "". |
entryPoint | string | no | Default "". |
healthCheckPath | string | no | Default /. |
dockerFilePath | string | no | Default ./Dockerfile. |
dockerBuildContextDir | string | no | Default ./. |
tier | { key: string } | no | Instance tier. |
disk | number | no | 0–100 GB, default 0. |
autoScaling | object | no | { enabled, minReplicas 1–50, maxReplicas 1–100, targetCpuPercent 1–100 }. |
autoDeploy | boolean | no | Default false. |
prPreview | boolean | no | Default false. |
enableAnalytics | boolean | no | Default false. |
env / secrets | EnvVar[] | no | Default []. |
slug: "auto" — CreateAutoInput
Section titled “slug: "auto" — CreateAutoInput”Let PandaStack detect static vs container from the repo. Same base fields as static/container but most build fields are optional overrides:
| Field | Type | Required | Notes |
|---|---|---|---|
slug | "auto" | yes | Discriminator. |
name | string | yes | RFC-1123 label. |
repositoryName | string | yes | owner/repo. |
branch | string | no | Default main. |
baseDir | string | no | Default ./. |
isPublic | boolean | no | Default true. |
autoDeploy / prPreview / enableAnalytics | boolean | no | Default false. |
env / secrets | EnvVar[] | no | Default []. |
buildCmd, buildDir, startCmd | string | no | Optional overrides. |
tier | { key: string } | no | |
disk | number | no | 0–100. |
autoScaling | object | no | See above. |
Response (CreateProjectResult):
| Field | Type | Notes |
|---|---|---|
projectId | number | |
name | string | |
deploymentId | number | First deploy row. |
deploymentUuid | string | Use to poll status / stream logs. |
curl -X POST https://api.pandastack.io/v1/projects \ -H "Authorization: Bearer $PANDASTACK_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "slug": "auto", "name": "my-app", "repositoryName": "acme/my-app", "branch": "main", "autoDeploy": true, "env": [{ "name": "NODE_ENV", "value": "production" }] }'{ "success": true, "data": { "projectId": 900, "name": "my-app", "deploymentId": 5501, "deploymentUuid": "d-8f3c2a1e" }}See Auto-detect deploys and Build & buildpacks.
Upload a static project (ZIP)
Section titled “Upload a static project (ZIP)”POST /v1/projects/static-upload
Create or re-upload a static project directly from a ZIP archive (no Git repo). The upload is content-abuse scanned, then stored in GCS.
Auth: member. Content-Type: multipart/form-data.
| Field | Type | Required | Notes |
|---|---|---|---|
staticFiles | file (ZIP) | yes | Max 30 MB. |
name | string | yes | RFC-1123 label. |
Response: { projectId, name, deploymentId, uploadId, liveUrl, fileCount }.
curl -X POST https://api.pandastack.io/v1/projects/static-upload \ -H "Authorization: Bearer $PANDASTACK_TOKEN" \ -F "name=my-static" \ -F "staticFiles=@site.zip"Check name availability
Section titled “Check name availability”GET /v1/projects/check-name
Auth: any member. Query: ?name=<candidate>. Response (NameAvailability): { name, available }.
curl "https://api.pandastack.io/v1/projects/check-name?name=my-app" \ -H "Authorization: Bearer $PANDASTACK_TOKEN"Get a project
Section titled “Get a project”GET /v1/projects/:name
Auth: any member. Returns the full ProjectDetail (see the project object).
curl https://api.pandastack.io/v1/projects/my-app \ -H "Authorization: Bearer $PANDASTACK_TOKEN"Delete a project
Section titled “Delete a project”DELETE /v1/projects/:name
Deletes the project and tears down its infrastructure. Static teardown is synchronous; container teardown is asynchronous via the worker.
Auth: admin. Response: { deleted: true, slug, async }.
curl -X DELETE https://api.pandastack.io/v1/projects/my-app \ -H "Authorization: Bearer $PANDASTACK_TOKEN"Rename a project
Section titled “Rename a project”PATCH /v1/projects/:name/name
Auth: member. Body (RenameProjectInput):
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | RFC-1123 label, 1–63 chars, ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$. |
Returns the updated ProjectDetail.
Update project config
Section titled “Update project config”PATCH /v1/projects/:name
Auth: member. Body (UpdateProjectInput) — all fields optional:
| Field | Type | Notes |
|---|---|---|
buildCmd | string | Max 2000. |
startCmd | string | Max 2000. |
baseDir | string | Max 500. |
buildDir | string | Max 500. |
healthCheckPath | string | Max 500. |
dockerFilePath | string | Max 500. |
disk | number | 0–1000. |
tier | { key: string } | Instance tier. |
autoScaling | object | { enabled, minReplicas 1–50, maxReplicas 1–100, targetCpuPercent 1–100 }. |
enableAnalytics | boolean | |
autoDeploy | boolean | |
env | EnvVar[] | Plaintext vars. |
secrets | SecretUpsert[] | Full replacement set. Omit an entry’s value to keep the stored one. |
Returns the updated ProjectDetail. When the save triggers an automatic redeploy (an env/secret/compute change on a container app), the response also carries triggeredDeploymentUuid so you can follow that build’s logs.
secrets replacement semantics. The array you send is the new secret set: a stored name you omit is deleted. An entry may leave out value, which means “keep whatever is stored under this name”. That is what lets a client hold only the values the user actually typed or revealed and still save safely — sending [{"name":"API_KEY"}] alongside a new secret preserves API_KEY rather than blanking it.
See Autoscaling & scale-to-zero and Environment variables & secrets.
List secret names
Section titled “List secret names”GET /v1/projects/:name/secrets
Auth: member. Returns [{ "name": string }] — names only, never values. Use it to show which secrets exist without exposing them.
Reveal a secret
Section titled “Reveal a secret”POST /v1/projects/:name/secrets/reveal
Auth: member. Body: { "name": string }. Returns { "name": string, "value": string } for that one secret, with Cache-Control: no-store.
POST rather than GET so the value never lands in a URL, an access log, or an intermediary cache. One secret per call — there is no bulk-dump endpoint. Every call is written to the project’s audit log with the secret’s name and the user who read it. Returns 404 if no secret by that name exists.
Enable / disable (pause) a static project
Section titled “Enable / disable (pause) a static project”POST /v1/projects/:name/toggle
Auth: member. Body (ToggleProjectInput): { "enable": boolean }. Returns ProjectDetail.
Roll back a project
Section titled “Roll back a project”POST /v1/projects/:name/rollback
Roll back to a previous deployment.
Auth: member. Body (RollbackInput): { "deploymentUuid": string }. Response: { deploymentUuid }.
curl -X POST https://api.pandastack.io/v1/projects/my-app/rollback \ -H "Authorization: Bearer $PANDASTACK_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "deploymentUuid": "d-previous-uuid" }'Deployments
Section titled “Deployments”Trigger a deploy
Section titled “Trigger a deploy”POST /v1/projects/:name/deploy
Triggers a deploy (create or redeploy), optionally at a specific commit. Writes a deployment row and an outbox event, then returns 202 (async).
Auth: member. Body:
| Field | Type | Required | Notes |
|---|---|---|---|
operation | string | no | Deploy operation hint. |
commitSha | string | no | Deploy a specific commit. |
Response: { deploymentId, deploymentUuid, projectId }.
curl -X POST https://api.pandastack.io/v1/projects/my-app/deploy \ -H "Authorization: Bearer $PANDASTACK_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "commitSha": "a1b2c3d4" }'Redeploy the current source
Section titled “Redeploy the current source”POST /v1/projects/:name/redeploy
Redeploys the current source; 202 async. Auth: member. Body: none. Response: { deploymentId, deploymentUuid, projectId }.
List deployments
Section titled “List deployments”GET /v1/projects/:name/deployments
Cursor-paginated list of a project’s deployments.
Auth: any member. Query (DeploymentListQuery): cursor (optional), limit (1–100, default 20).
Deployment object:
| Field | Type | Notes |
|---|---|---|
id | number | |
deploymentUuid | string | null | |
status | queued | running | succeeded | failed | string | |
commitId | string | null | |
commitSha | string | null | |
branch | string | null | |
enable | boolean | null | |
actor | object | { userId, name, username }. |
createdAt / updatedAt | string | null |
Get deployment status
Section titled “Get deployment status”GET /v1/deployments/:uuid/status
Read-once status of a deployment (the UI polls this).
Auth: any member. Response (DeploymentStatusInfo):
| Field | Type | Notes |
|---|---|---|
deploymentUuid | string | |
status | queued | running | succeeded | failed | string | |
terminal | boolean | true once the deploy has finished (succeeded or failed). |
commitId | string | null | |
branch | string | null | |
createdAt / updatedAt | string | null | |
projectName | string | null | |
repositoryName | string | null | |
projectUrl | string | null |
curl https://api.pandastack.io/v1/deployments/d-8f3c2a1e/status \ -H "Authorization: Bearer $PANDASTACK_TOKEN"Stream build logs
Section titled “Stream build logs”GET /v1/deployments/:uuid/logs/stream
Server-Sent Events stream of build logs. It replays history from Elasticsearch, tails live output, de-duplicates lines, and closes when the deploy reaches a terminal state (or after a 30-minute cap).
Auth: any member. Because this is SSE, pass the token (and org, for JWTs) as query params: ?access_token=<token>&organization_id=<orgId>. See SSE authentication.
Events emitted: log, system, status, done. Each log line matches the LogLine shape: { message, timestamp, stream } where stream is stdout | stderr | system.
curl -N "https://api.pandastack.io/v1/deployments/d-8f3c2a1e/logs/stream?access_token=$PANDASTACK_TOKEN&organization_id=1907"event: logdata: {"message":"Installing dependencies…","timestamp":"2026-07-14T10:00:03Z","stream":"stdout"}
event: statusdata: {"status":"running"}
event: donedata: {"status":"succeeded"}Custom domains
Section titled “Custom domains”Attach your own hostnames to a project. Domains are provisioned through Cloudflare custom hostnames (SSL-for-SaaS). Concept guide: Custom domains.
List custom domains
Section titled “List custom domains”GET /v1/projects/:name/domains
Auth: any member. Response: CustomDomain[].
Add a custom domain
Section titled “Add a custom domain”POST /v1/projects/:name/domains
Auth: member. Body: AddCustomDomainInput. Response: CustomDomain (returns DNS verification details to set at your registrar).
Verify a custom domain
Section titled “Verify a custom domain”POST /v1/domains/:domainId/verify
Re-checks a domain’s verification/SSL status.
Auth: any member. Response: CustomDomain.
Delete a custom domain
Section titled “Delete a custom domain”DELETE /v1/domains/:domainId
Auth: member. Response: { deleted: true }.
Redirects, rewrites & headers
Section titled “Redirects, rewrites & headers”Configure gateway routing rules per project. On containers these are synced to Kong. Concept guide: Redirects, rewrites & headers.
Get / set response headers
Section titled “Get / set response headers”GET /v1/projects/:name/headers (any member) — returns HeaderRule[].
PUT /v1/projects/:name/headers (member) — body SetHeadersInput; persisted to Postgres and Kong-synced for containers. Returns HeaderRule[].
Get / set redirects
Section titled “Get / set redirects”GET /v1/projects/:name/redirects (any member) — returns RedirectRule[].
PUT /v1/projects/:name/redirects (member) — body SetRedirectsInput; persisted to Postgres and Kong-synced. Returns RedirectRule[].
curl -X PUT https://api.pandastack.io/v1/projects/my-app/redirects \ -H "Authorization: Bearer $PANDASTACK_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "redirects": [{ "source": "/old", "destination": "/new", "status": 301 }] }'Related
Section titled “Related”- Metrics & analytics API — per-project performance and audience data.
- Databases API — link a database to a project.
- Integrations API — connect GitHub and marketplace services.