Skip to content

Create a new deployment

POST
/v1/apps/{appName}/deployments
curl --request POST \
--url https://api.aetherpush.com/v1/apps/example/deployments \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "name": "Beta" }'

Creates a new deployment channel under the app. Only accounts with the deployments.manage permission (Owner or Admin) can create deployments.

appName
required
string
Media typeapplication/json
object
name
required
string
>= 1 characters <= 255 characters
key

Optional pre-defined deployment key. If omitted, the server generates a secure random key. Pre-defined keys are useful when migrating from CodePush and need to preserve existing client deployments without redeploying app binaries. A key outside the length or character set above is refused with 400, so a migrated key containing other characters has to be rewritten on the client before the deployment is created.

string
>= 10 characters <= 100 characters /^[a-zA-Z0-9_-]+$/

Example

{
"name": "Beta"
}

Deployment created.

Media typeapplication/json
object
deployment
required
object
name
required
string
<= 255 characters
key

Deployment key consumed by the React Native SDK at runtime. Replaced with “(hidden)” for accounts without the deploymentKeys.read capability.

string
package
object
appVersion
string
blobUrl
required

Signed URL to download the package bundle.

string format: uri
description
string
isDisabled
boolean
isMandatory
boolean
isAutoHalted

True when this release is currently held by the automatic release halt: the package is disabled and a halt event exists at its current auto-halt generation. Present on GET /v1/apps/{appName}/deployments/{deploymentName}/history (and the paginated form of that route). False after an override re-enables the release, after a manual disable with no live halt event, or when the package is enabled. Omitted on Package responses that do not compute the flag.

boolean
label

Server-minted release id (for example v3). Omitted when the package has no label. Never null and never an empty string.

string
originalDeployment

Set when releaseMethod is Promote.

string
originalLabel

Set when releaseMethod is Promote or Rollback.

string
packageHash

SHA-256 hash of the package contents. The server computes this from the uploaded bytes; callers do not supply it.

string
releaseMethod
string
Allowed values: Upload Promote Rollback
rollout

Percentage of devices eligible for this release (1-100). Full rollout is always 100 in responses; the server stores completed rollouts as null and normalises them at the REST boundary.

integer
>= 1 <= 100
size
required

Package size in bytes.

integer format: int64
uploadTime

Unix timestamp in milliseconds.

integer format: int64

Example

{
"deployment": {
"name": "Production",
"key": "AbCdEf1234567890",
"package": {
"appVersion": "1.0.0",
"label": "v3",
"releaseMethod": "Upload"
}
}
}
Location
string

Validation error.

Media typeapplication/json
One of:
Error

Standard error envelope. code is the stable machine identifier for client branching and i18n. The wording of error is a human-readable fallback and is not part of the contract. Specialized responses keep narrower code enums where clients already branch on them.

object
error
required

Human-readable error message.

string
code
required

Stable machine code. Prefer this over matching on error. The values this API can answer with are listed in the ApiErrorCode schema of the raw document at https://api.aetherpush.com/openapi.yaml. The field stays an open string here so that a release adding a value does not invalidate this response.

string
requestId

Unique identifier for the request, also exposed as the X-Request-Id response header.

string

Example

{
"error": "The requested resource was not found.",
"code": "not_found",
"requestId": "req_abc123"
}

Unauthenticated.

Media typeapplication/json
Error

Standard error envelope. code is the stable machine identifier for client branching and i18n. The wording of error is a human-readable fallback and is not part of the contract. Specialized responses keep narrower code enums where clients already branch on them.

object
error
required

Human-readable error message.

string
code
required

Stable machine code. Prefer this over matching on error. The values this API can answer with are listed in the ApiErrorCode schema of the raw document at https://api.aetherpush.com/openapi.yaml. The field stays an open string here so that a release adding a value does not invalidate this response.

string
requestId

Unique identifier for the request, also exposed as the X-Request-Id response header.

string

Example

{
"error": "The requested resource was not found.",
"code": "not_found",
"requestId": "req_abc123"
}

The API key’s scopes do not grant apps, which answers required_scopes; or the caller’s role on the app does not grant deployments.manage, which answers a plain error. Access keys and login sessions hold wildcard scope, so they never receive the scope refusal. Other refusals raised before the route, such as a request that did not arrive through the trusted edge, also answer a plain error.

Media typeapplication/json
One of:
Error

Standard error envelope. code is the stable machine identifier for client branching and i18n. The wording of error is a human-readable fallback and is not part of the contract. Specialized responses keep narrower code enums where clients already branch on them.

object
error
required

Human-readable error message.

string
code
required

Stable machine code. Prefer this over matching on error. The values this API can answer with are listed in the ApiErrorCode schema of the raw document at https://api.aetherpush.com/openapi.yaml. The field stays an open string here so that a release adding a value does not invalidate this response.

string
requestId

Unique identifier for the request, also exposed as the X-Request-Id response header.

string

Examples

The API key's scopes do not grant apps

{
"error": "Insufficient permissions",
"code": "insufficient_scopes",
"required_scopes": [
"apps"
],
"requestId": "req_abc123"
}

App not found.

Media typeapplication/json
Error

Standard error envelope. code is the stable machine identifier for client branching and i18n. The wording of error is a human-readable fallback and is not part of the contract. Specialized responses keep narrower code enums where clients already branch on them.

object
error
required

Human-readable error message.

string
code
required

Stable machine code. Prefer this over matching on error. The values this API can answer with are listed in the ApiErrorCode schema of the raw document at https://api.aetherpush.com/openapi.yaml. The field stays an open string here so that a release adding a value does not invalidate this response.

string
requestId

Unique identifier for the request, also exposed as the X-Request-Id response header.

string

Example

{
"error": "The requested resource was not found.",
"code": "not_found",
"requestId": "req_abc123"
}

Two conditions answer this status: a deployment with that name already exists in this app (deployment_name_in_use), or the key is already registered on Aether (deployment_key_in_use). Deployment keys are unique across every app and every workspace, not per app, so a key held by an app you cannot see is still refused here. A generated key can also hit that index: keys are 256 bits of randomness and are not retried on collision.

Read code rather than error to tell the two apart. Error wording is not part of this contract. The name is checked before the insert and answers a message naming it plus deployment_name_in_use. A name lost to a concurrent create and a taken key both answer the generic conflict body, now with the matching code. code reports one unique; an insert that violates both still answers a single code. A conflict outside those two causes answers the plain error shape with resource_already_exists.

Listing the app’s deployments remains the complete discriminator. The name present with the key you sent means the deployment you wanted is already there and the retry is done; the name present with a different key is a name conflict; the name absent means another deployment already holds the key, either one listed here under a different name or one in another app, whether or not you can see it. deployment_name_in_use does not mean the key is free.

Media typeapplication/json
Any of:
Error

Standard error envelope. code is the stable machine identifier for client branching and i18n. The wording of error is a human-readable fallback and is not part of the contract. Specialized responses keep narrower code enums where clients already branch on them.

object
error
required

Human-readable error message.

string
code
required

Stable machine code. Prefer this over matching on error. The values this API can answer with are listed in the ApiErrorCode schema of the raw document at https://api.aetherpush.com/openapi.yaml. The field stays an open string here so that a release adding a value does not invalidate this response.

string
requestId

Unique identifier for the request, also exposed as the X-Request-Id response header.

string

Examples

This app already has a deployment with that name

{
"error": "A deployment named 'Beta' already exists.",
"code": "deployment_name_in_use",
"requestId": "req_abc123"
}

Two causes share this status. The tenant limiter answers RateLimitErrorResponse (error, retryAfterSeconds) with Retry-After. The plan’s per-app deployment quota answers the Error envelope and no Retry-After.

Media typeapplication/json
One of:
RateLimitError

Returned with HTTP 429 when an endpoint-specific rate limit is hit, including the per-tenant management API budget. Not the process-wide address limiter (see GlobalAddressRateLimitErrorResponse). retryAfterSeconds indicates how long the client should wait before retrying, and matches the Retry-After header when that header is set. code names the limit that fired so clients can translate without matching on error.

object
error
required
string
code
required
string
retryAfterSeconds
required
integer
>= 1
requestId
string

Examples

Tenant management budget spent

{
"error": "Rate limit exceeded",
"code": "tenant_rate_limit_exceeded",
"retryAfterSeconds": 60
}
Retry-After
integer
>= 1

Present only for the tenant limiter.

The deployment could not be created because of database contention on this app (lock wait expired, deadlock, or a serialization failure). No deployment was created. The body includes retryAfterSeconds and the response sets Retry-After to the same value.

Media typeapplication/json

Returned with HTTP 503 when the server could not complete an operation for a reason it expects to pass, and says so rather than answering as though it had. On the management API, a release or deployment write could not finish because of database contention (lock wait expired, deadlock, or a serialization failure) and nothing was written, or a release upload could not read back the package it had just stored in order to sign its URL. On the acquisition endpoints, a database read the request depends on could not be completed: resolving a deployment key with nothing cached for it, reading that deployment’s releases, or refreshing the download URL of the release it would serve. The release and download-URL reads answer this way for the failures the server recognises as transient, and the deployment lookup answers this way for any failure it cannot serve from a cached entry, so an outage no longer produces a different status depending on which of them it reached. retryAfterSeconds is the minimum interval before a retry is useful for the path that failed, and is also sent as the Retry-After response header. Management lock-contention 503s use the commit lock wait; acquisition and other transient-read 503s use the deployment-cache failure grace. Those intervals are independent and can differ. code is connection_failed on every response this schema describes, management lock contention included. The operation and the message are what distinguish the paths.

object
error
required
string
code
required
string
retryAfterSeconds
required
integer
>= 1
requestId
string

Example

{
"error": "This release could not finish because another release was committing to the same deployment. No release was created. Please try again.",
"code": "connection_failed",
"retryAfterSeconds": 5,
"requestId": "req_abc123"
}
Retry-After
integer

Seconds to wait before retrying.