Organizations & Teams API
Everything in PandaStack is scoped to an organization. Users belong to one or more orgs with a role (owner, admin, member, viewer), and orgs contain teams and members. BIGINT ids serialize as strings on the wire. Billing internals are deliberately absent from these shapes.
All routes require authentication. Some are identity-only (no active org needed); those are marked. Role floors are noted per endpoint.
viewer < member < admin < ownerSee Authentication — roles for what each role can do.
Current user
Section titled “Current user”GET /v1/me
The current user and the orgs they can act in. Called on boot, before an active org is selected — so it needs identity only.
Auth: authenticated (identity-only). Response (Me):
| Field | Type | Notes |
|---|---|---|
id | number | |
email | string | |
username | string | null | |
firstName / lastName | string | null | |
avatarUrl | string | null | |
mfaEnabled | boolean | |
organizations | OrgMembership[] | Each { organizationId, name, role, cardVerified }. |
Secrets (password, MFA secret, Firebase id) are never included.
curl https://api.pandastack.io/v1/me \ -H "Authorization: Bearer $PANDASTACK_TOKEN"whoami
Section titled “whoami”GET /v1/whoami
Resolve the current credential’s org and role (works for psk_ tokens and JWTs; used for CLI login discovery).
Auth: any member. Response: { userId, orgId, orgName, role }.
Organizations
Section titled “Organizations”List organizations
Section titled “List organizations”GET /v1/orgs
Orgs the caller belongs to.
Auth: authenticated (user-scoped). Response: Organization[].
Organization: { id, name, websiteLink, description, country, role, cardVerified }.
Create an organization
Section titled “Create an organization”POST /v1/orgs
Creates a new org; the caller becomes owner. Enforces the free-org quota.
Auth: authenticated (user-scoped). Body (CreateOrgInput): { name } — trimmed, 1–120 chars. Response: Organization.
curl -X POST https://api.pandastack.io/v1/orgs \ -H "Authorization: Bearer $PANDASTACK_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Acme Inc" }'Get an organization
Section titled “Get an organization”GET /v1/orgs/:id
The active org must match :id — no cross-org reads.
Auth: any member. Response: Organization.
List teams in the org
Section titled “List teams in the org”GET /v1/orgs/:id/teams
Auth: any member. Response: Team[] — each { id, name, organizationId }.
Account (org settings)
Section titled “Account (org settings)”Get account detail
Section titled “Get account detail”GET /v1/account
Full org detail (Settings → Account).
Auth: any member. Response (OrgDetail): { id, name, websiteLink, description, country, plan, memberCount, createdAt } where plan is free | pro | premium | enterprise.
Update account detail
Section titled “Update account detail”PATCH /v1/account
Auth: admin. Body (UpdateOrgInput) — all optional:
| Field | Type | Notes |
|---|---|---|
name | string | 1–120. |
websiteLink | string | null | Valid URL, max 300. |
description | string | null | Max 1000. |
country | string | null | Max 80. |
Response: OrgDetail.
Delete the org
Section titled “Delete the org”POST /v1/account/delete
Deletes the organization. Destructive and guarded by a type-to-confirm exact name.
Auth: owner. Body (DeleteOrgInput): { confirmName } — must exactly match the org name. Response: { success: true }.
curl -X POST https://api.pandastack.io/v1/account/delete \ -H "Authorization: Bearer $PANDASTACK_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "confirmName": "Acme Inc" }'Create a team
Section titled “Create a team”POST /v1/teams
Auth: admin. Body (CreateTeamInput): { name } — 1–120 chars. Response: Team.
Rename a team
Section titled “Rename a team”PATCH /v1/teams/:id
Auth: admin. Body: { name } (same as create). Response: Team.
Delete a team
Section titled “Delete a team”DELETE /v1/teams/:id
Auth: admin. Response: { deleted: true }.
List team members
Section titled “List team members”GET /v1/teams/:id/members
Members of a team in the active org (the team is org-checked).
Auth: any member (viewer+). Response: Member[].
Member: { userId, teamId, role, username, email, avatarUrl }.
Members & invitations
Section titled “Members & invitations”Invite a member
Section titled “Invite a member”POST /v1/teams/members
Invites a member; sends a Mailgun invite email best-effort.
Auth: admin. Body (InviteMemberInput):
| Field | Type | Required | Notes |
|---|---|---|---|
email | string | yes | Valid email. |
teamId | number | yes | Team to invite into. |
role | owner | admin | member | viewer | no | Default member. |
Response: Invitation.
curl -X POST https://api.pandastack.io/v1/teams/members \ -H "Authorization: Bearer $PANDASTACK_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "email": "new@example.com", "teamId": 3, "role": "member" }'Remove a member
Section titled “Remove a member”DELETE /v1/teams/:id/members/:userId
Auth: admin. Response: { removed: true }.
List invitations
Section titled “List invitations”GET /v1/invitations
Invitations for the active org.
Auth: any member. Response: Invitation[].
Invitation: { id, email, teamId, role, organizationId, status (invited|accepted|rejected), organizationName?, inviterName? }.
View an invitation
Section titled “View an invitation”GET /v1/invitations/:id
A single invitation’s details, from the invitee’s side (they are not yet a member).
Auth: authenticated (invitee). Response: Invitation.
Respond to an invitation
Section titled “Respond to an invitation”POST /v1/invitations/:id/respond
Accept or decline an invitation (email-matched to the caller).
Auth: authenticated (invitee). Body (RespondInvitationInput): { status: "accepted" | "rejected" }. Response: { status, organizationId }.
curl -X POST https://api.pandastack.io/v1/invitations/57/respond \ -H "Authorization: Bearer $PANDASTACK_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "status": "accepted" }'API tokens
Section titled “API tokens”Manage the psk_ tokens used for programmatic access. See Authentication for how tokens work.
List tokens
Section titled “List tokens”GET /v1/api-tokens
Auth: admin. Response: ApiToken[] (masked).
ApiToken: { id, name, description, status (active|revoked), preview ('psk_...a1b2'), lastUsed, expiresAt, createdAt }.
Create a token
Section titled “Create a token”POST /v1/api-tokens
The raw token is returned once.
Auth: admin. Body (CreateApiTokenInput):
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | 1–80 chars. |
description | string | no | Max 300. |
expiresInDays | number | no | 1–3650. |
permissions | record | no | Scoped permissions. |
Response (CreatedApiToken): { token (full psk_… secret, shown once), apiToken: ApiToken }.
curl -X POST https://api.pandastack.io/v1/api-tokens \ -H "Authorization: Bearer $PANDASTACK_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "ci-deploy", "expiresInDays": 90 }'Revoke a token
Section titled “Revoke a token”DELETE /v1/api-tokens/:id
Auth: admin. Response: { success: true }.
Notifications
Section titled “Notifications”The org’s in-app notification feed (bell). Written by the control plane and worker-v3 lifecycle events (e.g. db.expiring, db.suspended, db.purge_warning, db.purged). This route group is allowlisted past the card wall.
List notifications
Section titled “List notifications”GET /v1/notifications
Auth: any member. Query (NotificationListQuery): limit (default 30, max 100), unreadOnly (default false).
Response (NotificationListPage): { items: Notification[], unread (total unread count for the bell badge) }.
Notification: { id, type, title, body, resourceType, resourceId, read, createdAt }.
Mark one read
Section titled “Mark one read”POST /v1/notifications/:id/read
Auth: any member. Response: { success: true }.
Mark all read
Section titled “Mark all read”POST /v1/notifications/read-all
Auth: any member. Response: { success: true }.
Overview dashboard
Section titled “Overview dashboard”GET /v1/overview
The landing-dashboard aggregate: resource counts, 30-day deploy stats, and a 90-day daily deployment calendar (GitHub-style heatmap). Org-scoped, computed from Postgres.
Auth: any member. Response (Overview):
| Field | Type | Notes |
|---|---|---|
counts | object | { projects, containers, static, databases, functions, monitors }. |
deployments | object | { last30d, succeeded30d, failed30d, successRate }. |
calendar | DeploymentDay[] | Each { date ('YYYY-MM-DD'), total, succeeded, failed }. |
curl https://api.pandastack.io/v1/overview \ -H "Authorization: Bearer $PANDASTACK_TOKEN"Related
Section titled “Related”- Usage & limits API — team-member and team allowances by plan.
- Billing API — the org’s subscription and cards.