Skip to content

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. Secrets are never returned by any project endpoint — the env array carries only plaintext variables.

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.

ProjectDetail (returned by get / create-result-adjacent reads):

FieldTypeNotes
idnumber
namestring | nullSubdomain-safe name.
slugstatic | container | string | nullDeployment target.
branchstring | nullTracked branch.
repositoryNamestring | nullowner/repo.
organizationIdstringBIGINT serialized as string.
projectUrlstring | nullLive URL.
enabledbooleanWhether the project is active (see toggle).
isPublicboolean
languagestring | nulle.g. nodejs, python, go, docker.
runtimestring | null
regionstring | null
baseDirstring | nullBuild root directory.
buildDirstring | nullStatic output directory.
buildCmdstring | null
startCmdstring | nullContainer start command.
healthCheckPathstring | null
dockerFilePathstring | null
tierobject | nullInstance tier.
disknumber | nullPersistent disk (GB).
autoScalingobject | null{ enabled, minReplicas, maxReplicas, targetCpuPercent }.
enableAnalyticsboolean
autoDeploybooleanDeploy on push.
envEnvVar[]{ name, value }; secrets excluded.
totalDeploymentsnumber
successDeploymentsnumber
failedDeploymentsnumber
latestDeploymentobject | null{ status, commitId, createdAt }.
createdAt / updatedAtstring | null

ProjectListItem (returned in lists) is a compact subset: id, name, slug, branch, repositoryName, organizationId, projectUrl, enabled, latestDeployment, updatedAt.


GET /v1/projects

Cursor-paginated list of projects in the active org. Secrets are never returned.

Auth: any member.

Query params (ProjectListQuery):

ParamTypeRequiredNotes
cursorstringnoOpaque cursor from a prior nextCursor.
limitintno1–100, default 50.
slugstringnoFilter by static or container.
Terminal window
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
}
}

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.

FieldTypeRequiredNotes
slug"static"yesDiscriminator.
namestringyesRFC-1123 label: lowercase letters, numbers, hyphens; 1–63 chars.
repositoryNamestringyesowner/repo.
branchstringnoDefault main.
baseDirstringnoDefault ./.
buildDirstringnoDefault dist.
buildCmdstringnoDefault npm run build.
autoDeploybooleannoDefault false.
prPreviewbooleannoDefault false.
isPublicbooleannoDefault true.
enableAnalyticsbooleannoDefault false.
envEnvVar[]noDefault [].
secretsEnvVar[]noDefault []; stored base64, never returned.

slug: "container"CreateContainerInput

Section titled “slug: "container" — CreateContainerInput”
FieldTypeRequiredNotes
slug"container"yesDiscriminator.
namestringyesRFC-1123 label.
repositoryNamestringyesowner/repo.
branchstringnoDefault main.
regionstringnoDefault us.
languageenumyesauto | nodejs | python | go | docker.
isPublicbooleannoDefault true.
baseDirstringnoDefault ./.
buildCmdstringnoDefault "".
startCmdstringnoDefault "".
entryPointstringnoDefault "".
healthCheckPathstringnoDefault /.
dockerFilePathstringnoDefault ./Dockerfile.
dockerBuildContextDirstringnoDefault ./.
tier{ key: string }noInstance tier.
disknumberno0–100 GB, default 0.
autoScalingobjectno{ enabled, minReplicas 1–50, maxReplicas 1–100, targetCpuPercent 1–100 }.
autoDeploybooleannoDefault false.
prPreviewbooleannoDefault false.
enableAnalyticsbooleannoDefault false.
env / secretsEnvVar[]noDefault [].

Let PandaStack detect static vs container from the repo. Same base fields as static/container but most build fields are optional overrides:

FieldTypeRequiredNotes
slug"auto"yesDiscriminator.
namestringyesRFC-1123 label.
repositoryNamestringyesowner/repo.
branchstringnoDefault main.
baseDirstringnoDefault ./.
isPublicbooleannoDefault true.
autoDeploy / prPreview / enableAnalyticsbooleannoDefault false.
env / secretsEnvVar[]noDefault [].
buildCmd, buildDir, startCmdstringnoOptional overrides.
tier{ key: string }no
disknumberno0–100.
autoScalingobjectnoSee above.

Response (CreateProjectResult):

FieldTypeNotes
projectIdnumber
namestring
deploymentIdnumberFirst deploy row.
deploymentUuidstringUse to poll status / stream logs.
Terminal window
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.

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.

FieldTypeRequiredNotes
staticFilesfile (ZIP)yesMax 30 MB.
namestringyesRFC-1123 label.

Response: { projectId, name, deploymentId, uploadId, liveUrl, fileCount }.

Terminal window
curl -X POST https://api.pandastack.io/v1/projects/static-upload \
-H "Authorization: Bearer $PANDASTACK_TOKEN" \
-F "name=my-static" \
-F "staticFiles=@site.zip"

GET /v1/projects/check-name

Auth: any member. Query: ?name=<candidate>. Response (NameAvailability): { name, available }.

Terminal window
curl "https://api.pandastack.io/v1/projects/check-name?name=my-app" \
-H "Authorization: Bearer $PANDASTACK_TOKEN"

GET /v1/projects/:name

Auth: any member. Returns the full ProjectDetail (see the project object).

Terminal window
curl https://api.pandastack.io/v1/projects/my-app \
-H "Authorization: Bearer $PANDASTACK_TOKEN"

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 }.

Terminal window
curl -X DELETE https://api.pandastack.io/v1/projects/my-app \
-H "Authorization: Bearer $PANDASTACK_TOKEN"

PATCH /v1/projects/:name/name

Auth: member. Body (RenameProjectInput):

FieldTypeRequiredNotes
namestringyesRFC-1123 label, 1–63 chars, ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$.

Returns the updated ProjectDetail.

PATCH /v1/projects/:name

Auth: member. Body (UpdateProjectInput) — all fields optional:

FieldTypeNotes
buildCmdstringMax 2000.
startCmdstringMax 2000.
baseDirstringMax 500.
buildDirstringMax 500.
healthCheckPathstringMax 500.
dockerFilePathstringMax 500.
disknumber0–1000.
tier{ key: string }Instance tier.
autoScalingobject{ enabled, minReplicas 1–50, maxReplicas 1–100, targetCpuPercent 1–100 }.
enableAnalyticsboolean
autoDeployboolean
envEnvVar[]Plaintext vars.
secretsEnvVar[]Stored base64, never returned.

Returns the updated ProjectDetail. See Autoscaling & scale-to-zero and Environment variables & secrets.

POST /v1/projects/:name/toggle

Auth: member. Body (ToggleProjectInput): { "enable": boolean }. Returns ProjectDetail.

POST /v1/projects/:name/rollback

Roll back to a previous deployment.

Auth: member. Body (RollbackInput): { "deploymentUuid": string }. Response: { deploymentUuid }.

Terminal window
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" }'

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:

FieldTypeRequiredNotes
operationstringnoDeploy operation hint.
commitShastringnoDeploy a specific commit.

Response: { deploymentId, deploymentUuid, projectId }.

Terminal window
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" }'

POST /v1/projects/:name/redeploy

Redeploys the current source; 202 async. Auth: member. Body: none. Response: { deploymentId, deploymentUuid, projectId }.

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:

FieldTypeNotes
idnumber
deploymentUuidstring | null
statusqueued | running | succeeded | failed | string
commitIdstring | null
commitShastring | null
branchstring | null
enableboolean | null
actorobject{ userId, name, username }.
createdAt / updatedAtstring | null

GET /v1/deployments/:uuid/status

Read-once status of a deployment (the UI polls this).

Auth: any member. Response (DeploymentStatusInfo):

FieldTypeNotes
deploymentUuidstring
statusqueued | running | succeeded | failed | string
terminalbooleantrue once the deploy has finished (succeeded or failed).
commitIdstring | null
branchstring | null
createdAt / updatedAtstring | null
projectNamestring | null
repositoryNamestring | null
projectUrlstring | null
Terminal window
curl https://api.pandastack.io/v1/deployments/d-8f3c2a1e/status \
-H "Authorization: Bearer $PANDASTACK_TOKEN"

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.

Terminal window
curl -N "https://api.pandastack.io/v1/deployments/d-8f3c2a1e/logs/stream?access_token=$PANDASTACK_TOKEN&organization_id=1907"
event: log
data: {"message":"Installing dependencies…","timestamp":"2026-07-14T10:00:03Z","stream":"stdout"}
event: status
data: {"status":"running"}
event: done
data: {"status":"succeeded"}

Attach your own hostnames to a project. Domains are provisioned through Cloudflare custom hostnames (SSL-for-SaaS). Concept guide: Custom domains.

GET /v1/projects/:name/domains

Auth: any member. Response: CustomDomain[].

POST /v1/projects/:name/domains

Auth: member. Body: AddCustomDomainInput. Response: CustomDomain (returns DNS verification details to set at your registrar).

POST /v1/domains/:domainId/verify

Re-checks a domain’s verification/SSL status.

Auth: any member. Response: CustomDomain.

DELETE /v1/domains/:domainId

Auth: member. Response: { deleted: true }.


Configure gateway routing rules per project. On containers these are synced to Kong. Concept guide: Redirects, rewrites & 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 /v1/projects/:name/redirects (any member) — returns RedirectRule[].

PUT /v1/projects/:name/redirects (member) — body SetRedirectsInput; persisted to Postgres and Kong-synced. Returns RedirectRule[].

Terminal window
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 }] }'