Cosmoner Docs
API Reference

Apps

Managed app hosting. An app is either built from a git repository or runs a container image, and is created in two steps: save its configuration as a draft, then create the app from the draft, which charges the project's payment method and starts the first deployment. For an app running an image from one of the project's registries, `imageDeployPolicy` decides what a push to its repository does: `TAG` (the default) redeploys the app when the tag it uses is pushed again, and leaves other tags and an app pinned to a digest alone; `NEWEST` deploys whatever tag was pushed and switches the app to it; `MANUAL` does nothing, and the app moves only through Deploy image. **Environment variables at build time.** An app built from a repository gets its environment variables in the build as well as in the running container, so a value a framework inlines while building — `NEXT_PUBLIC_*`, `VITE_*` — is there. A plain variable is a build argument: a Dockerfile reads it with `ARG NAME`, and an auto-detected build or a static site's build command sees it in its environment without declaring anything. A variable marked secret is a BuildKit secret: it is mounted for the command that reads it and never written to an image layer, the image history or the build cache. A Dockerfile opts in per step with `RUN --mount=type=secret,id=NAME,env=NAME <command>`; auto-detected and static builds see it in the command's environment like a plain one. Names must be identifiers (`[A-Za-z_][A-Za-z0-9_]*`) — a variable named otherwise still reaches the container but is left out of the build. A changed variable is picked up by the next build: a push to the tracked branch, or Redeploy. Variables prefixed `RAILPACK_` also configure an auto-detected build; see the [Railpack reference](https://railpack.com/config/environment-variables). **Configuration file.** An app created from a repository's [configuration file](/docs/guides/app-templates) remembers which file and service it came from, and what the file applied. That is what lets Check configuration file tell the repository moving on apart from a setting changed in the control panel since; whether the file is then ignored, watched or applied on every push is the app's configuration file mode. Every call that changes an app is refused to members with the viewer role, and to a project blocked over an unpaid invoice (`403 ACCOUNT_BLOCKED`). Reading an app's network settings and its recent activity currently sits behind the same gate, and needs `apps:write` as well as `apps:read`. Four calls work with an API key but are not described operation by operation yet, because they answer with the app's full internal record, which is not a stable contract: listing apps (`GET /v1/projects/{projectId}/apps`, `apps:read`), reading one (`GET /v1/projects/{projectId}/apps/{appId}`, `apps:read`), updating its settings and environment variables (`PATCH /v1/projects/{projectId}/apps/{appId}`, `apps:write`) and changing its domain (`PATCH /v1/projects/{projectId}/apps/{appId}/domain`, `apps:write`). Rely only on the fields you also see in the control panel — `id`, `name`, `status`, `url`, the source and build settings, `envVars` — and expect the rest to change. Secret environment variable values come back masked, and a registry credential comes back without its password. Following an app's logs live and opening a console are available in the control panel; the latest log lines are available here.

POST
/v1/projects/{projectId}/apps

Creates the app a draft describes and starts its first deployment. The amount shown by Preview what an app will cost is charged to the project's payment method once the app has been created — normally before this call returns.

A project with no usable card, or with an unpaid invoice, is refused with 402 before anything is created — see Billing. If creating the app fails part-way, what was created is removed again.

When the draft asked for a database, it is created and billed first, exactly as creating a database on its own would be, and the response names it. The app stays DEPLOYING and its first deployment waits until the database is online. If the database fails to provision, it is removed and its charge reversed, the app is not deployed and becomes ERROR, and Retry database provisions it again. The app itself is charged once it has been created, after the database is online.

Members with the viewer role are refused, as is a project blocked over an unpaid invoice (403 ACCOUNT_BLOCKED).

Auth: a project API key carrying apps:write.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/projects/string/apps" \  -H "Content-Type: application/json" \  -d '{    "draftId": "string",    "size": "string"  }'
{  "success": true,  "data": {    "deployed": true,    "appId": "string",    "database": {      "id": "string",      "name": "string",      "secretName": "string",      "envVar": "string"    }  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
DELETE
/v1/projects/{projectId}/apps/{appId}

Tears the app down, removes its routing and stops billing for it. The unused part of the current period is credited to the project's balance.

If billing could not be stopped the answer is 502: the app is already taken down, but its record is kept so the deletion can be retried, and should be.

Members with the viewer role are refused, as is a project blocked over an unpaid invoice (403 ACCOUNT_BLOCKED).

Auth: a project API key carrying apps:write.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X DELETE "https://example.com/v1/projects/string/apps/string"
{  "success": true,  "data": {}}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
GET
/v1/projects/{projectId}/apps/{appId}/activity

The app's ten most recent deployments, newest first. Empty while the app is still being set up.

Registered behind the router's write gate, so it needs apps:write as well as apps:read and is refused to viewers, although it changes nothing.

Auth: a project API key carrying all of apps:read and apps:write.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/projects/string/apps/string/activity"
{  "success": true,  "data": [    {      "id": "string",      "type": "deploy",      "title": "string",      "actor": "string",      "commitSha": "string",      "commitUrl": "string",      "target": "string",      "timestamp": "2019-08-24T14:15:22Z",      "status": "success"    }  ]}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
GET
/v1/projects/{projectId}/apps/{appId}/config

Compares the app against the configuration file it was created from and reports what differs. Read-only in both directions: nothing about the app changes, and nothing is applied from the file. The file is read afresh on every call.

Auth: a project API key carrying apps:read.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/projects/string/apps/string/config"
{  "success": true,  "data": {    "checked": false,    "reason": "not_watched"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
PATCH
/v1/projects/{projectId}/apps/{appId}/config

Decides what the app's configuration file does from here on.

  • WATCH — compared against the app and reported. Nothing is written.
  • APPLY — also written on every push to the deployed branch, before the build, including over settings changed in the control panel. Needs auto-deploy on: the file is applied when a push is seen, and pushes are only seen for an app that deploys on push.
  • IGNORED — not read at all.

Turning auto-deploy off later leaves the mode set, but the file is not applied again until it is back on.

Members with the viewer role are refused, as is a project blocked over an unpaid invoice (403 ACCOUNT_BLOCKED).

Auth: a project API key carrying apps:write.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X PATCH "https://example.com/v1/projects/string/apps/string/config" \  -H "Content-Type: application/json" \  -d '{    "mode": "IGNORED"  }'
{  "success": true,  "data": {    "mode": "IGNORED"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
POST
/v1/projects/{projectId}/apps/{appId}/config/apply

Writes the settings the configuration file states onto the app. Every setting the file states replaces what the app has, including settings changed in the control panel; settings the file does not state are left alone.

instance_size and instances are never written from a file, however the request is made: they change what the app costs. They come back in skipped.

The settings are pushed to the app but not rebuilt: an environment variable or a port takes effect on the next deploy, and a build command applies to the next build. If the settings were written but could not be pushed, the answer is 502 with CONFIG_APPLIED_NOT_PUSHED, and they take effect on the next deploy.

Members with the viewer role are refused, as is a project blocked over an unpaid invoice (403 ACCOUNT_BLOCKED).

Auth: a project API key carrying apps:write.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/projects/string/apps/string/config/apply"
{  "success": true,  "data": {    "applied": [      "string"    ],    "skipped": [      {        "field": "string",        "reason": "billable"      }    ]  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
POST
/v1/projects/{projectId}/apps/{appId}/database/retry

For an app created with a database that failed to provision: provisions that database again and puts the app back to waiting for it. The app deploys once the database is online.

The database is the same one, with the same connection string, so the app's secret and link do not change. It is billed again from now, as when it was first created; the failed attempt's charge was reversed. Refused with 409 when the app is not waiting on a failed database (NO_DATABASE_TO_RETRY) or the database was deleted (DATABASE_DELETED).

Members with the viewer role are refused, as is a project blocked over an unpaid invoice (403 ACCOUNT_BLOCKED).

Auth: a project API key carrying all of apps:write and databases:write.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/projects/string/apps/string/database/retry"
{  "success": true,  "data": {    "appId": "string",    "databaseId": "string"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
POST
/v1/projects/{projectId}/apps/{appId}/deploy

Starts a fresh build of an app built from a repository, from the tip of its tracked branch — the retry after a failed build, or the way to roll out a change that did not come from a push. Apps that run an image use Deploy image instead.

Builds run on shared capacity, so this route is bounded on several sides. It answers 409 while the app already has a deployment in progress (DEPLOYMENT_IN_PROGRESS) or while the project already has as many builds running as it may (TOO_MANY_BUILDS_IN_PROGRESS) — retry once one settles. Rebuilding the same app again in quick succession answers 429 with DEPLOY_COOLDOWN, carrying the wait in a Retry-After header and in error.details.retryAfterSeconds. Deployments started by a push are not affected by any of this.

Members with the viewer role are refused, as is a project blocked over an unpaid invoice (403 ACCOUNT_BLOCKED).

Auth: a project API key carrying apps:write.

Rate limit: this endpoint is rate limited; a 429 means back off and retry.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/projects/string/apps/string/deploy"
{  "success": true,  "data": {    "deploymentPending": true  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
GET
/v1/projects/{projectId}/apps/{appId}/deployments

The app's twenty most recent deployments, newest first, in the shape Deploy image answers with. Each also says whether its image is the one the app runs now (current) and whether the app can be rolled back to it (rollbackable). Deployments still in progress include their steps; fetch a finished one to read its steps.

Auth: a project API key carrying apps:read.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/projects/string/apps/string/deployments"
{  "success": true,  "data": [    {      "id": "string",      "phase": "PENDING",      "cause": "string",      "imageRef": "string",      "imageDigest": "string",      "error": "string",      "startedAt": "2019-08-24T14:15:22Z",      "finishedAt": "2019-08-24T14:15:22Z",      "steps": [        {          "key": "string",          "status": "PENDING",          "detail": "string",          "error": "string",          "startedAt": "2019-08-24T14:15:22Z",          "finishedAt": "2019-08-24T14:15:22Z"        }      ],      "current": true,      "rollbackable": true    }  ]}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
POST
/v1/projects/{projectId}/apps/{appId}/deployments

Deploys an image app from the repository it already uses. This is the call for CI: push the image, then deploy the tag or digest you just pushed.

  • tag switches the app to that tag, e.g. sha-3f9c2a1.
  • digest pins the app to that manifest, sha256:…. A pinned app is not moved by pushes under the TAG deploy policy.

Send one or neither. With neither, the tag the app uses now is looked up again and deployed, which picks up a push the app's deploy policy did not follow.

Answers 202 with the deployment; the rollout continues after the response. Poll Fetch a deployment until phase is ACTIVE or ERROR. Deploying the image the app already runs returns that deployment again rather than starting another, so re-running a CI job is safe.

Only apps whose image is in one of the project's registries can be deployed this way.

Members with the viewer role are refused, as is a project blocked over an unpaid invoice (403 ACCOUNT_BLOCKED).

Auth: a project API key carrying apps:write.

Rate limit: this endpoint is rate limited; a 429 means back off and retry.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/projects/string/apps/string/deployments" \  -H "Content-Type: application/json" \  -d '{}'
{  "success": true,  "data": {    "id": "string",    "phase": "PENDING",    "cause": "string",    "imageRef": "string",    "imageDigest": "string",    "error": "string",    "startedAt": "2019-08-24T14:15:22Z",    "finishedAt": "2019-08-24T14:15:22Z",    "steps": [      {        "key": "string",        "status": "PENDING",        "detail": "string",        "error": "string",        "startedAt": "2019-08-24T14:15:22Z",        "finishedAt": "2019-08-24T14:15:22Z"      }    ]  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
GET
/v1/projects/{projectId}/apps/{appId}/deployments/{deploymentId}

One deployment, in the shape Deploy image answers with. A deployment still in progress is brought up to date before it is returned, so polling this sees it settle without delay.

Includes steps: the deployment as an ordered checklist, such as queued, build, starting the new version, the health check and live, each with its status and timing. A failed deployment marks the step it failed at with the reason, and skips the ones after it.

Auth: a project API key carrying apps:read.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length
deploymentId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/projects/string/apps/string/deployments/string"
{  "success": true,  "data": {    "id": "string",    "phase": "PENDING",    "cause": "string",    "imageRef": "string",    "imageDigest": "string",    "error": "string",    "startedAt": "2019-08-24T14:15:22Z",    "finishedAt": "2019-08-24T14:15:22Z",    "steps": [      {        "key": "string",        "status": "PENDING",        "detail": "string",        "error": "string",        "startedAt": "2019-08-24T14:15:22Z",        "finishedAt": "2019-08-24T14:15:22Z"      }    ]  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
POST
/v1/projects/{projectId}/apps/{appId}/deployments/{deploymentId}/rollback

Puts the app back on the image an earlier deployment ran, without building anything. Works for apps built from a repository and for image apps alike.

Only the image goes back. The app keeps its current environment variables and settings; values a build baked into the image are whatever they were when it was built.

  • An app built from a repository moves forward again with its next push, when it auto-deploys.
  • An image app is pinned to the rolled-back digest, so pushes under the TAG deploy policy no longer move it. Deploy a tag to follow pushes again.

Answers 202 with a new deployment, which settles like any other: poll Fetch a deployment until phase is ACTIVE or ERROR.

Members with the viewer role are refused, as is a project blocked over an unpaid invoice (403 ACCOUNT_BLOCKED).

Auth: a project API key carrying apps:write.

Rate limit: this endpoint is rate limited; a 429 means back off and retry.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length
deploymentId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/projects/string/apps/string/deployments/string/rollback"
{  "success": true,  "data": {    "id": "string",    "phase": "PENDING",    "cause": "string",    "imageRef": "string",    "imageDigest": "string",    "error": "string",    "startedAt": "2019-08-24T14:15:22Z",    "finishedAt": "2019-08-24T14:15:22Z",    "steps": [      {        "key": "string",        "status": "PENDING",        "detail": "string",        "error": "string",        "startedAt": "2019-08-24T14:15:22Z",        "finishedAt": "2019-08-24T14:15:22Z"      }    ]  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
GET
/v1/projects/{projectId}/apps/{appId}/logs

A snapshot of the app's build log (type=BUILD) or runtime log (type=RUN), whatever state the app is in. To follow a log as it is written, use the control panel.

Auth: a project API key carrying apps:read.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Query Parameters

type*string

Value in

  • "BUILD"
  • "RUN"

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/projects/string/apps/string/logs?type=BUILD"
{  "success": true,  "data": {    "lines": [      {        "message": "string",        "timestamp": "string"      }    ]  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
GET
/v1/projects/{projectId}/apps/{appId}/metrics

CPU and memory use, in percent, and restarts, each aggregated across the app's instances over range (1h by default). Readings are cached for up to a minute.

Auth: a project API key carrying apps:read.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Query Parameters

range?string
Default"1h"

Value in

  • "1h"
  • "6h"
  • "24h"

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/projects/string/apps/string/metrics"
{  "success": true,  "data": {    "cpu": [      {        "t": -9007199254740991,        "v": 0      }    ],    "memory": [      {        "t": -9007199254740991,        "v": 0      }    ],    "restarts": [      {        "t": -9007199254740991,        "v": 0      }    ]  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
GET
/v1/projects/{projectId}/apps/{appId}/network

The app's advanced network settings.

Registered behind the router's write gate, so it needs apps:write as well as apps:read and is refused to viewers, although it changes nothing.

Auth: a project API key carrying all of apps:read and apps:write.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/projects/string/apps/string/network"
{  "success": true,  "data": {    "advanced": {      "edgeCaching": true,      "emailObfuscation": true,      "threatProtection": true    }  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
PATCH
/v1/projects/{projectId}/apps/{appId}/network/advanced

Turns edge caching, email obfuscation and threat protection on or off. All three are sent every time. They are applied at the edge in front of the app's hostname, so the app is not redeployed.

Available once the app has an active hostname that is routed through the edge; a hostname pointed straight at the app (routingMode: direct) bypasses the edge, and is refused with 409 ADVANCED_NETWORKING_REQUIRES_EDGE. If the settings were saved but could not be applied, the answer is 502; send them again.

Members with the viewer role are refused, as is a project blocked over an unpaid invoice (403 ACCOUNT_BLOCKED).

Auth: a project API key carrying apps:write.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X PATCH "https://example.com/v1/projects/string/apps/string/network/advanced" \  -H "Content-Type: application/json" \  -d '{    "edgeCaching": true,    "emailObfuscation": true,    "threatProtection": true  }'
{  "success": true,  "data": {    "edgeCaching": true,    "emailObfuscation": true,    "threatProtection": true  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
GET
/v1/projects/{projectId}/apps/{appId}/previews

The app's previews, newest first: every live one, and those torn down in the last 30 days.

Auth: a project API key carrying apps:read.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/projects/string/apps/string/previews"
{  "success": true,  "data": [    {      "id": "string",      "appId": "string",      "gitProvider": "github",      "pullRequestNumber": -9007199254740991,      "pullRequestUrl": "string",      "headRepo": "string",      "headRef": "string",      "headSha": "string",      "status": "PENDING",      "url": "string",      "instanceSize": "string",      "lastBuild": {        "id": "string",        "phase": "PENDING",        "error": "string",        "startedAt": "2019-08-24T14:15:22Z",        "finishedAt": "2019-08-24T14:15:22Z"      },      "expiresAt": "2019-08-24T14:15:22Z",      "closedAt": "2019-08-24T14:15:22Z",      "createdAt": "2019-08-24T14:15:22Z",      "updatedAt": "2019-08-24T14:15:22Z"    }  ]}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
GET
/v1/projects/{projectId}/apps/{appId}/previews/{previewId}

One preview of the app.

Auth: a project API key carrying apps:read.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length
previewId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/projects/string/apps/string/previews/string"
{  "success": true,  "data": {    "id": "string",    "appId": "string",    "gitProvider": "github",    "pullRequestNumber": -9007199254740991,    "pullRequestUrl": "string",    "headRepo": "string",    "headRef": "string",    "headSha": "string",    "status": "PENDING",    "url": "string",    "instanceSize": "string",    "lastBuild": {      "id": "string",      "phase": "PENDING",      "error": "string",      "startedAt": "2019-08-24T14:15:22Z",      "finishedAt": "2019-08-24T14:15:22Z"    },    "expiresAt": "2019-08-24T14:15:22Z",    "closedAt": "2019-08-24T14:15:22Z",    "createdAt": "2019-08-24T14:15:22Z",    "updatedAt": "2019-08-24T14:15:22Z"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
DELETE
/v1/projects/{projectId}/apps/{appId}/previews/{previewId}

Stops the preview, removes it from its URL and marks it CLOSED. Its pull request is left alone, and the next push to it builds the preview again.

Tearing down a preview that is already torn down changes nothing and succeeds.

Members with the viewer role are refused, as is a project blocked over an unpaid invoice (403 ACCOUNT_BLOCKED).

Auth: a project API key carrying apps:write.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length
previewId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X DELETE "https://example.com/v1/projects/string/apps/string/previews/string"
{  "success": true,  "data": {    "id": "string",    "appId": "string",    "gitProvider": "github",    "pullRequestNumber": -9007199254740991,    "pullRequestUrl": "string",    "headRepo": "string",    "headRef": "string",    "headSha": "string",    "status": "PENDING",    "url": "string",    "instanceSize": "string",    "lastBuild": {      "id": "string",      "phase": "PENDING",      "error": "string",      "startedAt": "2019-08-24T14:15:22Z",      "finishedAt": "2019-08-24T14:15:22Z"    },    "expiresAt": "2019-08-24T14:15:22Z",    "closedAt": "2019-08-24T14:15:22Z",    "createdAt": "2019-08-24T14:15:22Z",    "updatedAt": "2019-08-24T14:15:22Z"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
GET
/v1/projects/{projectId}/apps/{appId}/previews/{previewId}/build-log

A snapshot of the build log of the preview's most recent build (lastBuild), in the shape Fetch logs answers with. Empty before the first build has written anything.

Auth: a project API key carrying apps:read.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length
previewId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/projects/string/apps/string/previews/string/build-log"
{  "success": true,  "data": {    "lines": [      {        "message": "string",        "timestamp": "string"      }    ]  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
GET
/v1/projects/{projectId}/apps/{appId}/previews/settings

Whether pull requests against the app's branch get previews, whether previews can be switched on for it, what they cost per hour and how many preview-hours ran this billing period, and which of its environment variables a preview receives. Secrets are never copied to a preview, so they are only counted.

Auth: a project API key carrying apps:read.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/projects/string/apps/string/previews/settings"
{  "success": true,  "data": {    "enabled": true,    "available": true,    "unavailableReason": "not_offered",    "price": {      "perHour": "string",      "currency": "string"    },    "hoursThisPeriod": 0,    "maxConcurrent": -9007199254740991,    "ttlHours": -9007199254740991,    "copiedVariables": [      {        "key": "string",        "source": "value"      }    ],    "omittedSecrets": -9007199254740991,    "gitPermissions": "granted"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
PATCH
/v1/projects/{projectId}/apps/{appId}/previews/settings

Turns pull request previews on or off for the app. Previews are off until switched on.

Previews are paid: switching them on accepts the hourly price shown in Fetch preview settings, billed for each preview for every hour it runs. Nothing is charged until a preview runs, and switching previews off stops the charge.

  • Switching on is refused while available is false in Fetch preview settings.
  • Switching on needs a project that can be charged: a saved payment method and no outstanding balance.
  • Switching off tears down every live preview of the app straight away.

Sending the state the app is already in changes nothing and succeeds.

Members with the viewer role are refused, as is a project blocked over an unpaid invoice (403 ACCOUNT_BLOCKED).

Auth: a project API key carrying apps:write.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X PATCH "https://example.com/v1/projects/string/apps/string/previews/settings" \  -H "Content-Type: application/json" \  -d '{    "enabled": true  }'
{  "success": true,  "data": {    "enabled": true,    "available": true,    "unavailableReason": "not_offered",    "price": {      "perHour": "string",      "currency": "string"    },    "hoursThisPeriod": 0,    "maxConcurrent": -9007199254740991,    "ttlHours": -9007199254740991,    "copiedVariables": [      {        "key": "string",        "source": "value"      }    ],    "omittedSecrets": -9007199254740991,    "gitPermissions": "granted"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
GET
/v1/projects/{projectId}/apps/{appId}/resize-preview

What moving the app to size costs now, and its new monthly price. Each of the app's instances is billed at the size's price, so both figures cover all of them. A downgrade is credited to the project's balance rather than charged; creditBack says how much.

A larger size needs room to run on. When there is none right now the answer is 409 (INSUFFICIENT_CAPACITY) instead of a quote, since Resize app would refuse the same move.

Auth: a project API key carrying apps:read.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Query Parameters

size*string
Match^[A-Za-z0-9][A-Za-z0-9._-]*$
Length1 <= length <= 64

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/projects/string/apps/string/resize-preview?size=string"
{  "success": true,  "data": {    "direction": "upgrade",    "subtotal": -9007199254740991,    "tax": -9007199254740991,    "creditApplied": -9007199254740991,    "dueToday": -9007199254740991,    "creditBack": -9007199254740991,    "currentMonthly": -9007199254740991,    "monthly": -9007199254740991,    "currency": "string",    "nextBillingDate": "2019-08-24T14:15:22Z"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
POST
/v1/projects/{projectId}/apps/{appId}/setup-routing

Points the app's hostname at it. For a Cosmoner subdomain or a domain whose DNS is managed here, that is done for you. For a hostname on a domain whose DNS is managed elsewhere, the answer carries the record to add there, and the hostname goes live once that record is in place — check with Verify custom hostname.

Safe to call repeatedly: it also repairs routing that has gone missing. Before the app's first deployment has an address, it answers deploymentPending and changes nothing.

Members with the viewer role are refused, as is a project blocked over an unpaid invoice (403 ACCOUNT_BLOCKED).

Auth: a project API key carrying apps:write.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/projects/string/apps/string/setup-routing"
{  "success": true,  "data": {    "deploymentPending": true  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
PATCH
/v1/projects/{projectId}/apps/{appId}/size

Moves the app to another size. The amount shown by Preview resize is charged to the project's payment method straight away, and the app is restarted on the new size, every instance it runs. Each instance is billed at the new size's price. A downgrade is credited to the project's balance and applied to future invoices rather than refunded to the card.

A larger size needs room to run on, for each of the app's instances. When there is none right now the request returns 409 (INSUFFICIENT_CAPACITY) and nothing is charged or changed; choose a smaller size or try again later. Moving to a smaller size is never refused for room.

If the card is declined the request returns 402 and the size is unchanged. If the app was resized and billed but the new size could not be applied yet, the answer is 502; the new size is applied on the next deployment.

Members with the viewer role are refused, as is a project blocked over an unpaid invoice (403 ACCOUNT_BLOCKED).

Auth: a project API key carrying apps:write.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X PATCH "https://example.com/v1/projects/string/apps/string/size" \  -H "Content-Type: application/json" \  -d '{    "size": "string"  }'
{  "success": true,  "data": {    "instanceSize": "string"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
GET
/v1/projects/{projectId}/apps/{appId}/sizes

The sizes this app can be moved to, cheapest first, together with the size it runs on today.

Auth: a project API key carrying apps:read.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/projects/string/apps/string/sizes"
{  "success": true,  "data": {    "currentSize": "string",    "resizable": true,    "sizes": [      {        "slug": "string",        "name": "string",        "tierSlug": "string",        "cpuType": "string",        "cpus": 0,        "memoryMb": -9007199254740991,        "bandwidthGib": 0,        "priceMonthly": 0      }    ],    "instances": 1  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
POST
/v1/projects/{projectId}/apps/{appId}/verify-hostname

Checks now whether a custom hostname has gone live, rather than waiting for the periodic check. The hostname counts as live once its certificate is issued, or once it is pointed straight at the app — in which case routingMode is direct.

Members with the viewer role are refused, as is a project blocked over an unpaid invoice (403 ACCOUNT_BLOCKED).

Auth: a project API key carrying apps:write.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length
appId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/projects/string/apps/string/verify-hostname"
{  "success": true,  "data": {    "routingStatus": "PENDING",    "routingMode": "edge",    "hostnameStatus": "string",    "sslStatus": "string"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
GET
/v1/projects/{projectId}/apps/deployable-registries

The registries an image app can be created from right now. A draft naming any other containerRegistry is refused with 409, so check here before saving one.

Auth: a project API key carrying apps:read.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length

Response Body

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/projects/string/apps/deployable-registries"
{  "success": true,  "data": {    "registries": [      "dockerhub"    ]  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
POST
/v1/projects/{projectId}/apps/draft

Saves an app's configuration as a draft, the first of the two steps that create an app. Nothing is provisioned or billed yet; pass the returned draftId to Create app. Drafts expire after 24 hours.

  • name must be unique within the project. A Cosmoner subdomain is generated from it and cannot be chosen; for an app on your own domain, set domainType and send the hostname in subdomain, with baseDomain (and targetFqdn for a subdomain of it).
  • Build from a repository with gitProvider, gitRepo and gitBranch. buildStrategy nixpacks detects how to build from the repository; docker builds its Dockerfile.
  • Or run an image with containerRegistry (see List deployable registries) and containerImage. For a private image on Docker Hub or the GitHub container registry, send containerCredentials as { "source": "dockerhub" } or { "source": "github" } to pull with the account connected to the project. imageDeployPolicy sets what a push to a project registry does to the app.
  • config — { path, serviceName, fileDigest } — records the repository configuration file the settings were filled from. The app then watches that file, so Check configuration file can later tell the repository moving on apart from settings changed afterwards.
  • database ({ plan, region?, version?, name?, secretName?, envVar? }) creates a PostgreSQL database together with the app. plan is a size from the database catalogue. Its connection string is stored as a project secret named secretName (default DATABASE_URL), the app is linked to the database, and the secret is injected as envVar (default: the secret's name). Not available for static sites. Needs the databases:write scope and a role that may create databases as well, and a secret name the project does not already use: an existing secret is never overwritten.

Members with the viewer role are refused, as is a project blocked over an unpaid invoice (403 ACCOUNT_BLOCKED).

Auth: a project API key carrying apps:write.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v1/projects/string/apps/draft" \  -H "Content-Type: application/json" \  -d '{    "size": "string",    "region": "string"  }'
{  "success": true,  "data": {    "draftId": "string"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
GET
/v1/projects/{projectId}/apps/preview

What creating an app of the given size would be charged today and each month after, including estimated tax and any project credit, before committing to it.

Send databasePlan as well to price an app created with a database (see Save a draft): the preview then covers both together, the way Create app charges them.

Each instance is billed at the size's price. Send instances to price the count the app will run; it defaults to one.

Auth: a project API key carrying apps:read.

AuthorizationBearer <token>

A project API key. X-API-Key: <key> is accepted as an alternative to the Authorization header.

In: header

Path Parameters

projectId*string
Length1 <= length

Query Parameters

size*string

The size to price, e.g. shared-s.

Match^[A-Za-z0-9][A-Za-z0-9._-]*$
Length1 <= length <= 64
databasePlan?string

A database plan to price together with the app, from the database catalogue.

Match^[A-Za-z0-9][A-Za-z0-9._-]*$
Length1 <= length <= 64
instances?integer

How many instances the app will run. Each is billed at the size's price. Defaults to 1.

Range0 < value <= 9007199254740991

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/projects/string/apps/preview?size=string"
{  "success": true,  "data": {    "subtotal": -9007199254740991,    "tax": -9007199254740991,    "creditApplied": -9007199254740991,    "dueToday": -9007199254740991,    "monthly": -9007199254740991,    "currency": "string",    "nextBillingDate": "2019-08-24T14:15:22Z"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}
{  "success": false,  "error": {    "code": "string",    "message": "string",    "details": {      "property1": null,      "property2": null    },    "issues": null,    "docsUrl": "http://example.com"  }}

On this page