Projects
Create, list, update, delete, and reprovision Amba projects; manage API keys.
Projects are the top-level unit of tenancy. Creating one provisions a fresh Neon database (via the PROJECT_PROVISIONING Temporal workflow), stores its connection string in GCP Secret Manager, runs tenant migrations, seeds system segments, and mints an initial client + server API key pair.
Source: apps/api/src/routes/admin/projects.ts.
Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /admin/projects | Create a project (+ initial API keys, kicks off provisioning). |
| GET | /admin/projects | List all projects owned by the developer. |
| GET | /admin/projects/:projectId | Project details + API keys + integrations. |
| PATCH | /admin/projects/:projectId | Update name, bundle id, platform, environment. |
| DELETE | /admin/projects/:projectId | Delete project row (does not tear down the Neon DB). |
| POST | /admin/projects/:projectId/api-keys | Mint an additional API key. |
| DELETE | /admin/projects/:projectId/api-keys/:keyId | Deactivate an API key. |
| POST | /admin/projects/:projectId/reprovision | Re-drive a failed or stalled provision. |
| GET | /admin/projects/:projectId/provisioning-status | Poll the Neon mapping + Temporal workflow status. |
POST /admin/projects
Create a project.
Request
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Display name. |
bundle_id | string | no | Mobile app bundle id (used as default Apple audience). |
platform | "ios" | "android" | "all" | no | Defaults to "all". |
Response 201
provisioning_status is "provisioning" if the Temporal workflow started, "failed" if it didn't (the project still exists — call POST /admin/projects/:projectId/reprovision to retry).
Errors
500 CREATE_FAILED— control plane write failed.
Try it:
/admin/projectscurl -X POST 'https://api.amba.dev/admin/projects'Curl:
GET /admin/projects
List all projects owned by the authenticated developer, newest first.
Response 200
Try it:
/admin/projectscurl -X GET 'https://api.amba.dev/admin/projects'Curl:
GET /admin/projects/:projectId
Fetch a single project with API keys (hashes only) and integrations.
Response 200
Errors
404 NOT_FOUND— project does not exist or is not owned by the developer.
Try it:
/admin/projects/%7B%7BprojectId%7D%7Dcurl -X GET 'https://api.amba.dev/admin/projects/%7B%7BprojectId%7D%7D'Curl:
PATCH /admin/projects/:projectId
Update mutable fields. Unknown fields are silently ignored.
Request
| Field | Type | Notes |
|---|---|---|
name | string | |
bundle_id | string | |
platform | "ios" | "android" | "all" | |
environment | string | Developer-chosen label. |
An empty body is a no-op that returns the current row.
Response 200
Errors
404 NOT_FOUND.500 UPDATE_FAILED.
Try it:
/admin/projects/%7B%7BprojectId%7D%7Dcurl -X PATCH 'https://api.amba.dev/admin/projects/%7B%7BprojectId%7D%7D'Curl:
DELETE /admin/projects/:projectId
Delete the control-plane project row. Does NOT delete the Neon DB — operate on the Neon console / Terraform to reclaim storage.
Response 200
Errors
404 NOT_FOUND.500 DELETE_FAILED.
Try it:
/admin/projects/%7B%7BprojectId%7D%7Dcurl -X DELETE 'https://api.amba.dev/admin/projects/%7B%7BprojectId%7D%7D'Curl:
POST /admin/projects/:projectId/api-keys
Mint an additional API key.
Request
| Field | Type | Required | Allowed values |
|---|---|---|---|
key_type | string | yes | "client", "server" |
environment | string | yes | "development", "production" |
Response 201
The full key is returned ONCE and never again — the control plane stores only a bcrypt-like hash.
Errors
400 INVALID_INPUT— badkey_typeorenvironment.404 NOT_FOUND.500 CREATE_FAILED.
Try it:
/admin/projects/%7B%7BprojectId%7D%7D/api-keyscurl -X POST 'https://api.amba.dev/admin/projects/%7B%7BprojectId%7D%7D/api-keys'Curl:
DELETE /admin/projects/:projectId/api-keys/:keyId
Deactivate (is_active = false) an API key. Subsequent requests with that key fail 401 UNAUTHORIZED.
Response 200
Errors
404 NOT_FOUND.500 REVOKE_FAILED.
Try it:
/admin/projects/%7B%7BprojectId%7D%7D/api-keys/%7B%7BkeyId%7D%7Dcurl -X DELETE 'https://api.amba.dev/admin/projects/%7B%7BprojectId%7D%7D/api-keys/%7B%7BkeyId%7D%7D'Curl:
POST /admin/projects/:projectId/reprovision
Re-drive a failed or stalled PROJECT_PROVISIONING workflow. Idempotent — duplicate POSTs collapse onto the same workflow id. Serialized under a DB row lock so two concurrent calls can't both start workflows.
Response 200
If a prior workflow is already running at the same millisecond, the response additionally includes "collapsed": true.
Errors
404 NOT_FOUND— project not owned by the developer.409 ALREADY_ACTIVE— project is already active; reprovision is not permitted.409 ARCHIVED— archived projects cannot be reprovisioned.409 PROVISIONING_IN_PROGRESS— a workflow is already running.error.details.workflow_id+.statusdescribe it.502 REPROVISION_FAILED— Temporal refused to start the workflow; the DB UPDATE was rolled back.500 REPROVISION_FAILED— unexpected error.
Try it:
/admin/projects/%7B%7BprojectId%7D%7D/reprovisioncurl -X POST 'https://api.amba.dev/admin/projects/%7B%7BprojectId%7D%7D/reprovision'Curl:
GET /admin/projects/:projectId/provisioning-status
Poll the current Neon mapping row and describe the latest provisioning workflow. Safe to poll every few seconds.
Response 200
mapping is null if no row exists yet. workflow is null if the mapping's current_workflow_id doesn't resolve to a Temporal execution (e.g. create-time failure where Temporal was never reached).
Errors
404 NOT_FOUND.500 PROVISIONING_STATUS_FAILED.
Try it:
/admin/projects/%7B%7BprojectId%7D%7D/provisioning-statuscurl -X GET 'https://api.amba.dev/admin/projects/%7B%7BprojectId%7D%7D/provisioning-status'Curl: