Skip to content

Schedule the current account for deletion

POST
/v1/account/deletion
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.

Media typeapplication/json
object
password
required

The account’s current password.

string
stepUp

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
type
required
string
Allowed values: passkey totp
response

WebAuthn AuthenticationResponseJSON. Required when type is passkey.

object
key
additional properties
any
code

A current authenticator code. Required when type is totp.

string

The deletion is scheduled and every credential of the account is revoked.

Media typeapplication/json
object
scheduledFor
required

When the purge runs, in epoch milliseconds: the start (UTC) of the day 30 days after the request.

integer format: int64

Example

{
"scheduledFor": 1791244800000
}

A missing password answers a plain error; a wrong one answers a validation error naming the field.

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"
}

Authentication required, or the account has MFA and no valid step-up proof was supplied (code: step_up_required).

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

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.

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

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.

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 account still owns something the deletion would orphan (code: account_deletion_blocked); reasons says what.

Media typeapplication/json

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
error
required
string
code
required
string
Allowed values: account_deletion_blocked
reasons
required
Array<string>
>= 1 items
Allowed values: apps subscription pending_transfer
requestId
string

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.

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 ten-per-hour budget for this account and address

{
"error": "Too many password attempts. Please try again later.",
"code": "too_many_password_attempts"
}

Internal server error.

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"
}