Aether
Overview
Multi-tenant OTA update platform for React Native apps.
Aether API 0.1.0
Section titled “Aether API 0.1.0”The Aether API powers over-the-air JavaScript bundle updates for React Native applications. It enables developers to push updates to deployed apps without going through the app store review process.
Authentication
Aether accepts two bearer credential families in the Authorization header:
- Access keys have wildcard scope and full account access. Login flows such
as POST /v1/auth/login create access keys with
isSession: true; dashboard and CLI sessions use these credentials, and only they satisfy session-only guards. Named access keys created through POST /v1/access-keys haveisSession: falseand cannot call session-only endpoints. - API keys use the
aether_sk_live_prefix and are created through POST /v1/api-keys. These long-lived credentials have scoped permissions for CI/CD pipelines and cannot call session-only endpoints.
See securitySchemes for details.
Versioning
All management and authentication endpoints are mounted under /v1. The canonical acquisition endpoints (consumed by the React Native SDK) live at /v1/public/aether/… Legacy acquisition paths (/v0.1/public/codepush/… and the camelCase /updateCheck and /reportStatus/… aliases) remain available for backward compatibility with the react-native-code-push SDK family and early Aether installs. Legacy paths return a Deprecation header and a Link header pointing to their canonical successor and to the CodePush migration guide.
Unsupported /v1 path-parameter aliases
The /v1 management mount falls through to the pre-/v1 router for any path the REST-shaped /v1 overrides do not handle. That fall-through still answers four path-parameter shapes that are not part of this published contract and must not be called:
- POST /v1/apps/{appName}/transfer/{email}
- POST /v1/apps/{appName}/collaborators/{email}
- POST /v1/apps/{appName}/deployments/{sourceDeploymentName}/promote/{destDeploymentName}
- POST /v1/apps/{appName}/deployments/{deploymentName}/rollback[/{targetRelease}]
They are omitted from the paths below on purpose. They send no Deprecation, Link, or Sunset header (those headers apply to bare legacy management mounts and to legacy acquisition, not to these /v1 shapes). Use the REST-shaped successors instead:
- POST /v1/apps/{appName}/transfers
- POST /v1/apps/{appName}/collaborators (email in the body; PATCH and DELETE on /collaborators/{email} remain documented)
- POST /v1/apps/{appName}/deployments/{sourceDeploymentName}/promotions
- POST /v1/apps/{appName}/deployments/{deploymentName}/rollbacks
The openapi-route-contract test’s UNDOCUMENTED_V1_ROUTES list is the mechanical census of this omission; keep that list and this section in step.
Error envelope
All error responses share a canonical shape with an error string
field, a stable code string field, and an optional requestId
string field. Validation failures additionally include an errors
array whose entries each carry their own code. See the Error
and ValidationErrorResponse schemas under components. Prefer
matching on code over matching on error wording. Every value an
operation in this document can answer with is listed in the
ApiErrorCode schema, published in full in the raw document at
https://api.aetherpush.com/openapi.yaml. The set follows the server
release, so treat an unrecognised value by its HTTP status alone.
CLI device-flow
OAuth responses are the exception: they keep the RFC machine value
in error and do not add a parallel code.
JSON request bodies parsed by the JSON body parser are refused with
413 and error set to “The provided resource is too large.” when
they exceed 10 KB (10,240 bytes). That parser does not run on
POST /v1/billing/webhook, which uses a raw parser with a 100 KB
limit, or on the multipart release upload. The release upload
answers 413 in the same Error envelope when the package exceeds
UPLOAD_SIZE_LIMIT_MB (default 50), when more than one file is
uploaded, or when the multipart body has too many parts; error
names which limit fired.
The requestId is also exposed as the X-Request-Id response header on every response and should be quoted when reporting issues.
Process-wide address limiter
Every published path on this API sits behind one process-wide
address limiter mounted ahead of routing (100 requests per
minute per client address). When that budget is spent the server
answers HTTP 429 with Content-Type: application/json and body
GlobalAddressRateLimitErrorResponse
({"error":"Too many requests","code":"too_many_requests"}), plus
Retry-After and draft RateLimit-* headers (standardHeaders,
no legacy X-RateLimit-*). The body does not carry
retryAfterSeconds or requestId; X-Request-Id is still set as
a header. No published route skips this limiter. Route-specific and
tenant limiters documented on individual operations are separate
budgets that can also answer 429 with different envelopes after
this one admits the request.
Authentication
Section titled “Authentication”accessKeyAuth
Section titled “accessKeyAuth”Wildcard bearer credential backed by access_keys. Login flows create
credentials with isSession: true; POST /v1/access-keys creates named
credentials with isSession: false. Operations that require a login
session, including billing endpoints, reject the named subtype.
While the account has a deletion scheduled (Account.deletionScheduledFor
is set), every authenticated operation answers a plain 403 except
GET /v1/account, DELETE /v1/account/deletion,
DELETE /v1/sessions/current and GET /v1/authenticated, which only
reports that the bearer is live. Signing in stays possible so the owner
can cancel; the freeze lifts the moment the deletion is cancelled.
Security scheme type: http
Bearer format: AccessKey
apiKeyAuth
Section titled “apiKeyAuth”Long-lived API key with the prefix aether_sk_live_. Created via
POST /v1/api-keys. Carries a granular scope set declared at
creation time. Cannot be used for billing endpoints or for
session/access-key management, both of which require a login session.
Scope enforcement: every management route enforces the scope shown
on its operation. deploy and apps also grant read, so a key does
not need read listed explicitly to call the reads a deploy or app
workflow depends on. See ApiKeyScope for the full rule.
Security scheme type: http
Bearer format: ApiKey