<!-- Generated from openapi/v2.json (md/account.md) — do not edit. Run: npm run generate -->

[Interactive reference](https://api-docs.syllaby.io/) · [OpenAPI 3.1 spec](https://api-docs.syllaby.io/openapi/v2.json) · [Docs index (llms.txt)](https://api-docs.syllaby.io/llms.txt)

# Account

The authenticated user — profile, per-feature credit costs, and the credit ledger.

## GET /me

**Get current account** (operationId: `getMyAccount`)

Returns the authenticated user's public account profile: identity, credit balance, and a high-level subscription summary (no billing-provider internals).

### Response `200`

```json
{
  "message": "Success.",
  "status": 200,
  "data": {
    "id": 1,
    "name": "Jane Doe",
    "email": "jane@example.com",
    "email_verified": true,
    "credits": {
      "remaining": 120,
      "total": 150,
      "extra": 0
    },
    "subscription": {
      "exists": true,
      "active": true,
      "trial": false,
      "plan": "Pro",
      "ends_at": "2026-02-01T00:00:00+00:00"
    },
    "created_at": "2026-01-01T12:00:00.000000Z",
    "updated_at": "2026-01-01T12:00:00.000000Z"
  }
}
```

### Errors

- `401` — Unauthenticated
- `405` — The URL exists but not for this HTTP method — e.g. `GET /presets/faceless/{preset}`, which is only defined for `PATCH` and `DELETE`. Check the verb against the endpoint reference; the `Allow` header lists the methods this path accepts.
- `409` — Email address not verified. The token is valid and the account exists, but the user has not confirmed their email address. This gate fronts every v2 endpoint. Have the user complete verification, then retry.
- `429` — Rate limit exceeded — requests are limited per API token (30 per minute by default). The response carries `Retry-After` (seconds to wait) and `X-RateLimit-Reset` (Unix timestamp when the window resets); back off until then and retry. Successful responses include `X-RateLimit-Limit` and `X-RateLimit-Remaining` so you can pace requests proactively.

Error shapes and examples are shared across endpoints — see the **Error responses** section in [getting-started](getting-started.md).

## GET /credits/costs

**List credit costs** (operationId: `listCreditCosts`)

Returns the per-feature credit cost map so you can show users what each action will cost before they spend credits.

### Response `200`

```json
{
  "message": "Success.",
  "status": 200,
  "data": {
    "idea_discovery": {
      "credits": 15
    },
    "avatar": {
      "credits": 30
    },
    "faceless": {
      "credits": 13
    },
    "image_regenerations": {
      "credits": 1,
      "free": 3
    },
    "thumbnail_generation": {
      "credits": 3
    }
  }
}
```

### Errors

- `401` — Unauthenticated
- `405` — The URL exists but not for this HTTP method — e.g. `GET /presets/faceless/{preset}`, which is only defined for `PATCH` and `DELETE`. Check the verb against the endpoint reference; the `Allow` header lists the methods this path accepts.
- `409` — Email address not verified. The token is valid and the account exists, but the user has not confirmed their email address. This gate fronts every v2 endpoint. Have the user complete verification, then retry.
- `429` — Rate limit exceeded — requests are limited per API token (30 per minute by default). The response carries `Retry-After` (seconds to wait) and `X-RateLimit-Reset` (Unix timestamp when the window resets); back off until then and retry. Successful responses include `X-RateLimit-Limit` and `X-RateLimit-Remaining` so you can pace requests proactively.

Error shapes and examples are shared across endpoints — see the **Error responses** section in [getting-started](getting-started.md).

## GET /credits/history

**List credit history** (operationId: `listCreditHistory`)

Returns the authenticated user's credit ledger (debits and credits), newest first by default. Pass `order=ASC` to reverse, and `per_page` to set the page size (default 12, max 50).

### Parameters

- `order` (query, string) — Sort direction by date. `DESC` (newest first, default) or `ASC`. Example: `DESC`
- `per_page` (query, integer) — Number of entries per page. Defaults to 12; capped at 50. Example: `12`
- `page` (query, integer) — Page number of the paginated ledger (see `links`/`meta` in the response). Example: `2`
- `source` (query, string) — Filter entries by origin. Use `api` to see only spend made through the public API. Example: `api`

### Response `200`

```json
{
  "message": "Success.",
  "status": 200,
  "data": [
    {
      "label": "Faceless video",
      "content_type": "Faceless video generated",
      "credit_spend": "-30",
      "transaction_type": "Debit",
      "created_at": "2026-01-01T12:00:00.000000Z"
    }
  ],
  "meta": {
    "current_page": 1,
    "per_page": 15,
    "total": 1
  }
}
```

### Errors

- `401` — Unauthenticated
- `405` — The URL exists but not for this HTTP method — e.g. `GET /presets/faceless/{preset}`, which is only defined for `PATCH` and `DELETE`. Check the verb against the endpoint reference; the `Allow` header lists the methods this path accepts.
- `409` — Email address not verified. The token is valid and the account exists, but the user has not confirmed their email address. This gate fronts every v2 endpoint. Have the user complete verification, then retry.
- `429` — Rate limit exceeded — requests are limited per API token (30 per minute by default). The response carries `Retry-After` (seconds to wait) and `X-RateLimit-Reset` (Unix timestamp when the window resets); back off until then and retry. Successful responses include `X-RateLimit-Limit` and `X-RateLimit-Remaining` so you can pace requests proactively.

Error shapes and examples are shared across endpoints — see the **Error responses** section in [getting-started](getting-started.md).

## GET /account/auto-topup

**Get auto top-up preference** (operationId: `getAutoTopUp`)

Returns the authenticated account's auto top-up preference: whether it's enabled, how it's configured, and its failure/enablement history.

Auto top-up automatically purchases more credits when your **API-originated** balance runs low — credits spent through the v2 API count toward the trigger; credits spent in the Syllaby app do not. It fires once your balance drops below **10%** of your monthly plan credits, purchasing either a fixed credit pack (`type: extra-credits`) or a custom amount (`type: dynamic-credits`), depending on how it's configured. Purchased credits land in your account's **extra credits**, on top of your plan allowance, and a notification is sent for both successful and failed attempts.

**Safeguards:** at most **3** successful top-ups per UTC calendar day; a failed charge starts a **24-hour cooldown** before the next attempt is made; and **3 consecutive failures** disable the preference automatically (`enabled` flips to `false` — `consecutive_failures` tells you how close it is).

See `PUT /account/auto-topup` for how enabling/disabling works and what a lapsed subscription means for this preference.

### Response `200`

```json
{
  "message": "Success.",
  "status": 200,
  "data": {
    "enabled": true,
    "type": "dynamic-credits",
    "plan_id": null,
    "units": 5,
    "enabled_at": "2026-01-01T12:00:00.000000Z",
    "consecutive_failures": 0
  }
}
```

### Errors

- `401` — Unauthenticated
- `403` — No active **paid** subscription. The v2 public API is paid-only — every faceless and preset endpoint (reads included) requires an active paid subscription, and trials are not eligible. Two codes distinguish the cause on this `403`: `PAID-SUBSCRIPTION-REQUIRED` (subscribed but on a trial — access unlocks automatically once the subscription becomes paid) and `SUBSCRIPTION-REQUIRED` (never subscribed, expired, or canceled). Rejected before any ownership, credit, or validation check. Only `GET /me`, `GET /credits/costs`, and `GET /credits/history` are reachable without a paid subscription.
- `405` — The URL exists but not for this HTTP method — e.g. `GET /presets/faceless/{preset}`, which is only defined for `PATCH` and `DELETE`. Check the verb against the endpoint reference; the `Allow` header lists the methods this path accepts.
- `409` — Email address not verified. The token is valid and the account exists, but the user has not confirmed their email address. This gate fronts every v2 endpoint. Have the user complete verification, then retry.
- `429` — Rate limit exceeded — requests are limited per API token (30 per minute by default). The response carries `Retry-After` (seconds to wait) and `X-RateLimit-Reset` (Unix timestamp when the window resets); back off until then and retry. Successful responses include `X-RateLimit-Limit` and `X-RateLimit-Remaining` so you can pace requests proactively.

Error shapes and examples are shared across endpoints — see the **Error responses** section in [getting-started](getting-started.md).

## PUT /account/auto-topup

**Update auto top-up preference** (operationId: `updateAutoTopUp`)

Enables, reconfigures, or disables auto top-up. Counters (`consecutive_failures`, the daily success count) survive toggling — disabling and re-enabling neither resets the failure history nor bypasses the daily cap.

**Disabling** — send `{ "enabled": false }`. Every other field is ignored, and the existing `type`/`plan_id`/`units` configuration is preserved for a future re-enable.

**Enabling** (`enabled: true`) additionally requires:
- `type` — `extra-credits` (also requires `plan_id`, an active one-time credit-pack plan) or `dynamic-credits` (also requires `units`).
- A saved default payment method on the account. Without one, the request fails with `422` (`A saved payment method is required to enable auto top-up.`).

**A lapsed subscription blocks this whole endpoint** — `GET` and `PUT /account/auto-topup` both sit behind the paid-subscription gate (`403`, below), the same as every other v2 endpoint. The preference itself is retained while lapsed and can still be reviewed or changed from the Syllaby web app; auto top-up resumes automatically once the subscription is active again.

### Request body

Required. `enabled` is always required. Disabling accepts just `enabled: false`; enabling additionally requires `type`, plus `plan_id` or `units` depending on it.

- `enabled` (boolean, required) — Turn auto top-up on or off. `false` disables it immediately; every other field is ignored when disabling.
- `type` (string) — Required when `enabled` is `true`. Purchase mode: `extra-credits` buys a fixed one-time credit pack (set `plan_id`), `dynamic-credits` buys a custom amount (set `units`). Allowed values: `extra-credits`, `dynamic-credits`.
- `plan_id` (integer) — Required when `type` is `extra-credits`. Identifier of an active one-time credit-pack plan.
- `units` (integer) — Required when `type` is `dynamic-credits`. Number of pricing units to purchase — 100 credits per unit. Up to 100 units, only preset values are accepted (1, 2, 3, 4, 5, 10, 20, 30, 50, 100); above 100 (up to 199,999) any integer is accepted.

Example request:

```json
{
  "enabled": true,
  "type": "dynamic-credits",
  "units": 5
}
```

### Response `200`

```json
{
  "message": "Success.",
  "status": 200,
  "data": {
    "enabled": true,
    "type": "dynamic-credits",
    "plan_id": null,
    "units": 5,
    "enabled_at": "2026-01-01T12:00:00.000000Z",
    "consecutive_failures": 0
  }
}
```

### Errors

- `401` — Unauthenticated
- `403` — No active **paid** subscription. The v2 public API is paid-only — every faceless and preset endpoint (reads included) requires an active paid subscription, and trials are not eligible. Two codes distinguish the cause on this `403`: `PAID-SUBSCRIPTION-REQUIRED` (subscribed but on a trial — access unlocks automatically once the subscription becomes paid) and `SUBSCRIPTION-REQUIRED` (never subscribed, expired, or canceled). Rejected before any ownership, credit, or validation check. Only `GET /me`, `GET /credits/costs`, and `GET /credits/history` are reachable without a paid subscription.
- `405` — The URL exists but not for this HTTP method — e.g. `GET /presets/faceless/{preset}`, which is only defined for `PATCH` and `DELETE`. Check the verb against the endpoint reference; the `Allow` header lists the methods this path accepts.
- `409` — Email address not verified. The token is valid and the account exists, but the user has not confirmed their email address. This gate fronts every v2 endpoint. Have the user complete verification, then retry.
- `422` — Validation error
- `429` — Rate limit exceeded — requests are limited per API token (30 per minute by default). The response carries `Retry-After` (seconds to wait) and `X-RateLimit-Reset` (Unix timestamp when the window resets); back off until then and retry. Successful responses include `X-RateLimit-Limit` and `X-RateLimit-Remaining` so you can pace requests proactively.

Error shapes and examples are shared across endpoints — see the **Error responses** section in [getting-started](getting-started.md).
