---
title: "Account and API keys API"
description: "Check API health, read the account and available generation balance behind an API key, and create, list, or revoke scoped API keys."
canonical_url: https://lyricwinter.com/docs/api/account
markdown_url: https://lyricwinter.com/docs/api/account.md
last_updated: 2026-10-05
status: beta
---
# LyricWinter API reference: Account and API keys

> Check API health, read the account and available generation balance behind an API key, and create, list, or revoke scoped API keys.

The LyricWinter API is in beta. Base URL: `https://lyricwinter.com/api/v1`. Authenticate every request with `Authorization: Bearer lw_...`. Successful responses are wrapped as `{ "data": ..., "request_id": "req_..." }`. Machine-readable contract: https://lyricwinter.com/api/v1/openapi.json.

## Endpoints

- [Check API health](https://lyricwinter.com/docs/api/account#get-health): `GET /health`
- [Get the current account](https://lyricwinter.com/docs/api/account#get-current-account-profile): `GET /me`
- [Read generation preferences](https://lyricwinter.com/docs/api/account#get-generation-preferences): `GET /me/generation-preferences`
- [Save generation preferences](https://lyricwinter.com/docs/api/account#update-generation-preferences): `PATCH /me/generation-preferences`
- [Get the current account balance](https://lyricwinter.com/docs/api/account#get-current-account-balance): `GET /me/balance`
- [Get available Studio funding and actions](https://lyricwinter.com/docs/api/account#get-studio-account-capabilities): `GET /studio/account-capabilities`
- [List API keys](https://lyricwinter.com/docs/api/account#list-api-keys): `GET /api-keys`
- [Create an API key](https://lyricwinter.com/docs/api/account#create-api-key): `POST /api-keys`
- [Revoke an API key](https://lyricwinter.com/docs/api/account#revoke-api-key): `DELETE /api-keys/{apiKeyId}`

### Check API health

`GET /health`

Authentication: none · Operation ID: `getHealth`

Returns a static payload when the LyricWinter API is reachable. It needs no authentication and performs no account checks.

#### Response 200

Stable API health response.

Fields inside `data`:

- `ok` (true; required)
- `service` ("lyricwinter"; required)
- `version` ("v1"; required)

#### Example request

```bash
curl "https://lyricwinter.com/api/v1/health" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
```

### Get the current account

`GET /me`

Scope: `account:read` · Operation ID: `getCurrentAccountProfile`

Returns the profile of the account that owns the API key: its ID, username, display name, avatar URL, and email.

#### Response 200

Current account profile.

Fields inside `data`:

- `profile` (object; required)
  - `id` (string; required)
  - `username` (string | null, 3–30 chars; required)
  - `name` (string | null, max 100 chars; required)
  - `image` (string | null, uri; required)
  - `email` (string | null, email; required)

Errors: `401`, `403`, `500` return the standard error envelope.

#### Example request

```bash
curl "https://lyricwinter.com/api/v1/me" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
```

### Read generation preferences

`GET /me/generation-preferences`

Scope: `account:read` · Operation ID: `getGenerationPreferences`

Read the account's saved Allow fallbacks setting. New accounts start with it enabled. The preference is shared across devices.

#### Response 200

Saved generation preference.

Fields inside `data`:

- `allow_fallbacks` (boolean; required)

Errors: `401`, `403`, `500` return the standard error envelope.

#### Example request

```bash
curl "https://lyricwinter.com/api/v1/me/generation-preferences" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
```

### Save generation preferences

`PATCH /me/generation-preferences`

Scope: `account:write` · Operation ID: `updateGenerationPreferences`

Save Allow fallbacks by sending allow_fallbacks as true or false. The response contains the saved value. Changing this preference does not alter work already submitted.

#### Request body (application/json, required)

- `allow_fallbacks` (boolean; required)

#### Response 200

Saved generation preference.

Fields inside `data`:

- `allow_fallbacks` (boolean; required)

Errors: `400`, `401`, `403`, `500` return the standard error envelope.

#### Example request

```bash
curl -X PATCH "https://lyricwinter.com/api/v1/me/generation-preferences" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "allow_fallbacks": true
}'
```

### Get the current account balance

`GET /me/balance`

Scope: `account:read` · Operation ID: `getCurrentAccountBalance`

Returns the caller's current account generation balance with `account:read`. `data.balance.snowcoins` is settled; `data.balance.available_snowcoins` is available after outstanding holds. For promotional credits and the combined Studio balance, use `/studio/account-capabilities` with `studio:read`. These values are current snapshots, not historical balances for billing activity. The server still reserves and charges credits atomically. Subscription state and usage history are separate resources.

#### Response 200

Cached balance and subscription-adjacent state for the authenticated caller.

Fields inside `data`:

- `balance` (object; required)
  - `snowcoins` (integer | null, ≥ 0; required): Current settled account Snowcoins.
  - `available_snowcoins` (integer | null, ≥ 0; required): Current spendable account Snowcoins after active holds.
  - `billing_debt` (integer, ≥ 0; required)
  - `subscription_tier` (string, one of `zerowinter`, `mywinter`, `ultrawinter`, `hyperwinter`; required)
  - `subscription_provider` (string | null, one of `stripe`, `app_store`; required)
  - `subscription_status` (string, one of `free`, `active`, `grace_period`, `billing_retry`, `expired`, `revoked`; required)
  - `has_active_subscription` (boolean; required)
  - `parse_limit_characters` (integer, ≥ 1; required)
  - `unlimited_f5_tts` (boolean; required)
  - `auto_reload_enabled` (boolean; required)
  - `auto_reload_threshold` (number | null; required)
  - `small_word_packs_eligible` (boolean; required)
  - `small_word_pack_eligibility` (object; required)
    - `canUseSmallWordPacks` (boolean; required)
    - `activeSubscription` (boolean; required)
    - `previousSuccessfulPayment` (boolean; required)
    - `engagedReturningUser` (boolean; required)
    - `completedAudioRunsLast30Days` (integer, ≥ 0; required)
    - `accountAgeDays` (integer | null, ≥ 0; required)
    - `accountCreatedAt` (string | null, date-time; required)

Errors: `401`, `403`, `500` return the standard error envelope.

#### Example request

```bash
curl "https://lyricwinter.com/api/v1/me/balance" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
```

### Get available Studio funding and actions

`GET /studio/account-capabilities`

Scope: `studio:read` · Operation ID: `getStudioAccountCapabilities`

Returns the caller's account balance, promotional Studio credits, plan, and action capabilities with `studio:read`. `data.studio_funding.total_available_snowcoins` and `total_available_words` include both account and promotional funding after holds. `as_of` identifies the snapshot. Actions are advisory, not a live provider-health check or a guarantee that a later paid request will succeed. Reading this endpoint can claim an eligible account reward before returning the snapshot; repeated reads do not grant the same reward twice.

#### Response 200

Current Studio account capabilities from one consistent billing snapshot.

Fields inside `data`:

- `schema_version` ("studio-account-capabilities-4"; required)
- `as_of` (string, date-time; required)
- `plan` (object; required)
  - `tier` (string, one of `zerowinter`, `mywinter`, `ultrawinter`, `hyperwinter`; required)
  - `display_name` (string; required)
  - `character_limit` (integer, ≥ 1; required)
- `balance` (object; required)
  - `settled_snowcoins` (integer, ≥ 0; required)
  - `held_snowcoins` (integer, ≥ 0; required)
  - `available_snowcoins` (integer, ≥ 0; required)
  - `settled_words` (integer, ≥ 0; required)
  - `held_words` (integer, ≥ 0; required)
  - `available_words` (integer, ≥ 0; required)
- `studio_funding` (object; required)
  - `promotional` (object; required)
    - `available_snowcoins` (integer, ≥ 0; required)
    - `held_snowcoins` (integer, ≥ 0; required)
    - `available_words` (integer, ≥ 0; required)
    - `held_words` (integer, ≥ 0; required)
    - `grants` (array of object; required)
      - `campaign_key` (string; required)
      - `display_name` (string; required)
      - `available_snowcoins` (integer, ≥ 0; required)
      - `held_snowcoins` (integer, ≥ 0; required)
      - `available_words` (integer, ≥ 0; required)
      - `held_words` (integer, ≥ 0; required)
      - `expires_at` (string | null, date-time; required)
  - `total_available_snowcoins` (integer, ≥ 0; required)
  - `total_held_snowcoins` (integer, ≥ 0; required)
  - `total_available_words` (integer, ≥ 0; required)
  - `total_held_words` (integer, ≥ 0; required)
- `campaign_dialogs` (array of object, max 20 items; required)
  - `campaign_key` (string, pattern ^[a-z0-9][a-z0-9_]{2,63}$; required)
  - `campaign_kind` (string, one of `promotion`, `customer_referral`, `affiliate`, `announcement`, `product_update`; required)
  - `priority` (integer, -1000–1000; required)
  - `content_revision` (integer, ≥ 1; required)
  - `interaction` (string, one of `claim`, `acknowledge`; required)
  - `title` (string, 1–120 chars; required)
  - `body` (string, 1–1000 chars; required)
  - `primary_action_label` (string, 1–80 chars; required)
  - `secondary_action_label` (string | null, 1–80 chars; required)
  - `learn_more_url` (string | null, uri, pattern ^https://; required)
  - `available_until` (string, date-time; required)
  - `rewards` (array of object, max 20 items; required)
    - `reward_key` (string; required)
    - `reward_type` ("studio_words"; required)
    - `amount_snowcoins` (integer, ≥ 1; required)
    - `amount_words` (integer, ≥ 1; required)
    - `expiration_policy` (string, one of `none`, `fixed`, `rolling`; required)
    - `fixed_expires_at` (string | null, date-time; required)
    - `expires_in_seconds` (integer | null, ≥ 1; required)
- `campaign_offers` (array of object, max 20 items; required)
  - `campaign_key` (string, pattern ^[a-z0-9][a-z0-9_]{2,63}$; required)
  - `campaign_kind` (string, one of `promotion`, `customer_referral`, `affiliate`, `announcement`, `product_update`; required)
  - `priority` (integer, -1000–1000; required)
  - `content_revision` (integer, ≥ 1; required)
  - `interaction` (string, one of `claim`, `acknowledge`; required)
  - `title` (string, 1–120 chars; required)
  - `body` (string, 1–1000 chars; required)
  - `primary_action_label` (string, 1–80 chars; required)
  - `secondary_action_label` (string | null, 1–80 chars; required)
  - `learn_more_url` (string | null, uri, pattern ^https://; required)
  - `available_until` (string, date-time; required)
  - `rewards` (array of object, max 20 items; required)
    - `reward_key` (string; required)
    - `reward_type` ("studio_words"; required)
    - `amount_snowcoins` (integer, ≥ 1; required)
    - `amount_words` (integer, ≥ 1; required)
    - `expiration_policy` (string, one of `none`, `fixed`, `rolling`; required)
    - `fixed_expires_at` (string | null, date-time; required)
    - `expires_in_seconds` (integer | null, ≥ 1; required)
- `purchases` (object; required)
  - `small_word_packs_eligible` (boolean; required)
- `actions` (object; required)
  - `prepare_text` (object; required)
    - `status` (string, one of `available`, `not_connected`; required)
    - `billing_mode` (string, one of `included`, `metered_snowcoins`, `not_applicable`; required)
  - `speech_generation` (object; required)
    - `status` (string, one of `available`, `not_connected`; required)
    - `billing_mode` (string, one of `included`, `metered_snowcoins`, `not_applicable`; required)
  - `sfx_generation` (object; required)
    - `status` (string, one of `available`, `not_connected`; required)
    - `billing_mode` (string, one of `included`, `metered_snowcoins`, `not_applicable`; required)
  - `voice_design` (object; required)
    - `status` (string, one of `available`, `not_connected`; required)
    - `billing_mode` (string, one of `included`, `metered_snowcoins`, `not_applicable`; required)
  - `voice_cloning` (object; required)
    - `status` (string, one of `available`, `not_connected`; required)
    - `billing_mode` (string, one of `included`, `metered_snowcoins`, `not_applicable`; required)
  - `final_render` (object; required)
    - `status` (string, one of `available`, `not_connected`; required)
    - `billing_mode` (string, one of `included`, `metered_snowcoins`, `not_applicable`; required)

Errors: `401`, `403`, `500` return the standard error envelope.

#### Example request

```bash
curl "https://lyricwinter.com/api/v1/studio/account-capabilities" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
```

### List API keys

`GET /api-keys`

Scope: `api_keys:read` · Operation ID: `listApiKeys`

Lists metadata for the account's API keys, including name, scopes, expiry, last use, and revocation time. Raw keys are never returned.

#### Response 200

Caller-owned API key metadata without raw key material or token hashes.

Fields inside `data`:

- `api_keys` (array of object; required)
  - `id` (string, uuid; required)
  - `name` (string, 1–80 chars; required)
  - `token_prefix` (string, pattern ^lw_[A-Za-z0-9_-]{8,32}$; required): Safe display prefix for identifying a key.
  - `scopes` (array of string, one of `account:read`, `account:write`, `api_keys:read`, `api_keys:write`, `audio_runs:read`, `audio_runs:write`, `billing:read`, `billing:write`, `demo_videos:read`, `demo_videos:write`, `feedback:write`, `projects:read`, `projects:write`, `reactions:read`, `reactions:write`, `stories:read`, `stories:write`, `studio:read`, `studio:write`, `voice_pins:read`, `voice_pins:write`, `voice_actors:read`, `voice_shares:read`, `voice_shares:write`, `voices:read`, `voices:write`; required)
  - `expires_at` (string | null, date-time; required)
  - `last_used_at` (string | null, date-time; required)
  - `revoked_at` (string | null, date-time; required)
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; required)

Errors: `401`, `403`, `500` return the standard error envelope.

#### Example request

```bash
curl "https://lyricwinter.com/api/v1/api-keys" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
```

### Create an API key

`POST /api-keys`

Scope: `api_keys:write` · Operation ID: `createApiKey`

Creates a scoped API key. The response contains `raw_key` exactly once; LyricWinter stores only a hash. When you call this endpoint with an API key, the new key can only have scopes that the calling key already holds.

#### Request body (application/json, required)

- `name` (string, 1–80 chars; required)
- `scopes` (array of string, min 1 items, one of `account:read`, `account:write`, `api_keys:read`, `api_keys:write`, `audio_runs:read`, `audio_runs:write`, `billing:read`, `billing:write`, `demo_videos:read`, `demo_videos:write`, `feedback:write`, `projects:read`, `projects:write`, `reactions:read`, `reactions:write`, `stories:read`, `stories:write`, `studio:read`, `studio:write`, `voice_pins:read`, `voice_pins:write`, `voice_actors:read`, `voice_shares:read`, `voice_shares:write`, `voices:read`, `voices:write`; required): Duplicate scopes are accepted and deduplicated.
- `expires_at` (string | null, date-time; optional): Optional expiration timestamp. Null or omitted creates a non-expiring key.

#### Response 201

API key created. The raw key is returned only in this response.

Fields inside `data`:

- `api_key` (object; required)
  - `id` (string, uuid; required)
  - `name` (string, 1–80 chars; required)
  - `token_prefix` (string, pattern ^lw_[A-Za-z0-9_-]{8,32}$; required): Safe display prefix for identifying a key.
  - `scopes` (array of string, one of `account:read`, `account:write`, `api_keys:read`, `api_keys:write`, `audio_runs:read`, `audio_runs:write`, `billing:read`, `billing:write`, `demo_videos:read`, `demo_videos:write`, `feedback:write`, `projects:read`, `projects:write`, `reactions:read`, `reactions:write`, `stories:read`, `stories:write`, `studio:read`, `studio:write`, `voice_pins:read`, `voice_pins:write`, `voice_actors:read`, `voice_shares:read`, `voice_shares:write`, `voices:read`, `voices:write`; required)
  - `expires_at` (string | null, date-time; required)
  - `last_used_at` (string | null, date-time; required)
  - `revoked_at` (string | null, date-time; required)
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; required)
- `raw_key` (string, pattern ^lw_[A-Za-z0-9_-]{8,32}_[A-Za-z0-9_-]+$; required): Display-once raw API key. The server stores only a SHA-256 hash.

Errors: `400`, `401`, `403`, `409`, `500` return the standard error envelope.

#### Example request

```bash
curl -X POST "https://lyricwinter.com/api/v1/api-keys" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "My integration",
  "scopes": [
    "account:read"
  ]
}'
```

### Revoke an API key

`DELETE /api-keys/{apiKeyId}`

Scope: `api_keys:write` · Operation ID: `revokeApiKey`

Revokes one of the account's API keys immediately. Revoking a key that is already revoked succeeds without changes.

#### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `apiKeyId` | string, uuid | Yes |  |

#### Response 200

Caller-owned API key was revoked, or was already revoked.

Fields inside `data`:

- `ok` (true; required)
- `api_key` (object; required)
  - `id` (string, uuid; required)
  - `name` (string, 1–80 chars; required)
  - `token_prefix` (string, pattern ^lw_[A-Za-z0-9_-]{8,32}$; required): Safe display prefix for identifying a key.
  - `scopes` (array of string, one of `account:read`, `account:write`, `api_keys:read`, `api_keys:write`, `audio_runs:read`, `audio_runs:write`, `billing:read`, `billing:write`, `demo_videos:read`, `demo_videos:write`, `feedback:write`, `projects:read`, `projects:write`, `reactions:read`, `reactions:write`, `stories:read`, `stories:write`, `studio:read`, `studio:write`, `voice_pins:read`, `voice_pins:write`, `voice_actors:read`, `voice_shares:read`, `voice_shares:write`, `voices:read`, `voices:write`; required)
  - `expires_at` (string | null, date-time; required)
  - `last_used_at` (string | null, date-time; required)
  - `revoked_at` (string | null, date-time; required)
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; required)

Errors: `400`, `401`, `403`, `404`, `500` return the standard error envelope.

#### Example request

```bash
curl -X DELETE "https://lyricwinter.com/api/v1/api-keys/$API_KEY_ID" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
```

