Schedule the current account for deletion
const url = 'https://api.aetherpush.com/v1/account/deletion';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"password":"example","stepUp":{"type":"passkey","response":{},"code":"example"}}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.aetherpush.com/v1/account/deletion \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "password": "example", "stepUp": { "type": "passkey", "response": {}, "code": "example" } }'Dashboard sessions only. Verifies the password and, when the account
has MFA, consumes a fresh step-up proof on the same transaction. Refuses
with 409 while the account is the Owner of an app or its workspace has
a paid plan, a Stripe subscription or an open checkout. Otherwise
schedules the purge for the start (UTC) of the day 30 days out, signs
out every session, revokes every access key of the account (CLI
credentials and named keys alike, so a CI pipeline using one starts
failing with 401 at once) and every API key, and freezes the account: until the deletion is cancelled every
other authenticated operation answers 403 (see accessKeyAuth). Signing
in stays possible so the owner can cancel. Revoked credentials are not
restored by a cancel. The purge deletes the account’s workspace when it
is the sole owner, and only the account otherwise; audit rows keep the
account id, the client address and the workspace’s Stripe customer id
under the privacy policy’s fraud-prevention and billing carve-outs,
with the purged email scrubbed out of them. After a tenant-mode purge
commits, the Stripe customer is deleted; Stripe keeps invoices and
payment records under its own retention. Account-mode purges leave the
Stripe customer with the surviving workspace and clear
tenants.billing_email when it matches the purged account email. A
Stripe outage during deletion does not undo the purge; the delete is
retried from an outbox. If an app or a paid plan reappeared
during the window, the purge cancels the deletion instead, the account
is active again and an email says why. A second request while one is
already scheduled receives the plain 403 described on accessKeyAuth.
The same two failure budgets as the password change apply, and this
route shares them with it. An email names the date.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
The account’s current password.
Fresh proof of a second factor the account already holds, required to change the factor set once MFA is enabled. A stolen session cannot enrol its own factor and then strip the owner’s. Recovery codes and passwords are deliberately not accepted here: a recovery code recovers a login but never authorizes a factor change.
object
WebAuthn AuthenticationResponseJSON. Required when type is passkey.
object
A current authenticator code. Required when type is totp.
Responses
Section titled “Responses”The deletion is scheduled and every credential of the account is revoked.
object
When the purge runs, in epoch milliseconds: the start (UTC) of the day 30 days after the request.
Example
{ "scheduledFor": 1791244800000}A missing password answers a plain error; a wrong one answers a validation error naming the field.
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
Human-readable error message.
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.
Unique identifier for the request, also exposed as the X-Request-Id response header.
object
object
Stable machine code for this field error.
Example
{ "error": "The requested resource was not found.", "code": "not_found", "requestId": "req_abc123"}Authentication required, or the account has MFA and no valid step-up proof was supplied (code: step_up_required).
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
Human-readable error message.
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.
Unique identifier for the request, also exposed as the X-Request-Id response header.
Returned when a factor-set change on an MFA-enabled account arrives
without a fresh step-up proof. Same shape as the reauth response so
clients branch on code and open the step-up flow, not on message text.
object
Example
{ "error": "The requested resource was not found.", "code": "not_found", "requestId": "req_abc123"}API keys and named access keys receive a plain 403. A login session
that is not a dashboard login session receives code
dashboard_session_required.
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
Human-readable error message.
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.
Unique identifier for the request, also exposed as the X-Request-Id response header.
Returned after login-session validation when a valid session that is
not a dashboard login session tries to issue or widen an API key,
create an access key or change its lifetime, enrol a passkey or
authenticator app, start a passkey step-up challenge, run the CLI
device ceremony, change the password, or request or cancel the
account’s deletion. Endpoints that enforce both guards reject API keys and
named access keys earlier with a plain 403 carrying
code: session_required. API-key creation applies only the
dashboard-session guard, so any non-dashboard credential receives
this response there. Listing,
renaming and revoking stay open to any login session. Sessions created
before the credential_origin column existed cannot be attributed to
the dashboard and are also refused; signing out and back in fixes that.
object
Example
{ "error": "This operation requires a login session. API keys and named access keys cannot access it.", "code": "session_required", "requestId": "req_abc123"}The account, or its workspace, no longer exists.
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
Human-readable error message.
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.
Unique identifier for the request, also exposed as the X-Request-Id response header.
Example
{ "error": "The requested resource was not found.", "code": "not_found", "requestId": "req_abc123"}The account still owns something the deletion would orphan (code: account_deletion_blocked); reasons says what.
Returned when deleting the account would orphan something. apps: the
account is the Owner of at least one app; delete those apps or complete
a cross-workspace transfer first. pending_transfer: an outbound
cross-workspace transfer is still pending; cancel it or wait for the
recipient to accept. subscription: the account’s workspace is on a
paid plan, holds a Stripe subscription, or has a checkout in progress;
cancel it first. Same shape as the other coded errors so clients branch
on code.
object
Example
{ "error": "The account cannot be deleted yet. Remove or transfer the apps it owns, cancel any pending transfer, and cancel its paid plan first, then try again.", "code": "account_deletion_blocked", "reasons": [ "apps" ]}Too many failed requests. Two budgets apply, and either one answers
429: ten per hour per account and client address, and twenty per
hour per account across all addresses. This route shares both with
changePassword. They are reached only after the session guards and
the pending-deletion freeze have admitted the caller, so the plain
401, the 403 for an API key or a named access key, the
dashboard_session_required 403 and the freeze 403 all spend
nothing. Everything the route answers past that point spends a unit
on both budgets, including the step_up_required 401, the
account_deletion_blocked 409, the 403 answered when a concurrent
request has already scheduled the deletion, a wrong password and a
malformed body. A deletion that is accepted spends nothing, so a
caller that sends stepUp together with the password succeeds in
one request and spends nothing at all; only a caller that discovers
the requirement by being refused spends a unit on that refusal.
The tenant management limiter can also answer 429, with
RateLimitErrorResponse (error, retryAfterSeconds) and Retry-After,
before those budgets.
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
Human-readable error message.
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.
Unique identifier for the request, also exposed as the X-Request-Id response header.
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
Examples
The ten-per-hour budget for this account and address
{ "error": "Too many password attempts. Please try again later.", "code": "too_many_password_attempts"}The twenty-per-hour budget for this account across all addresses
{ "error": "Too many password attempts on this account. Please try again later, or sign out every session if you did not make them.", "code": "too_many_password_attempts"}Tenant management budget spent
{ "error": "Rate limit exceeded", "code": "tenant_rate_limit_exceeded", "retryAfterSeconds": 60}Internal server 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
Human-readable error message.
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.
Unique identifier for the request, also exposed as the X-Request-Id response header.
Example
{ "error": "The requested resource was not found.", "code": "not_found", "requestId": "req_abc123"}