# Ancher Mux API

Ancher Mux lets users subscribe to YouTube channels and podcast shows, automatically transcribe and translate their content, and read summaries in their preferred language.

Base URL: `http://127.0.0.1:8080`

## Response Format

All endpoints return HTTP 200 with JSON: `{ "code": 0, "message": "...", "data": { ... } }`. Code 0 means success, non-zero means error.

## Authentication

Most endpoints require `Authorization: Bearer <token>`.

To get a token:
1. `POST /user/login/email/code` with `{ "email": "..." }` — sends verification code
2. `POST /user/login/email` with `{ "email": "...", "code": "..." }` — returns `{ "user_id": "..." }` in data, JWT token in the response `Authorization` header

The server may return a refreshed token in the `Authorization` response header on any request. When present, replace your stored token.

## Common Parameters

- `language` — `en`. Used for localized content display.
- `limit` — page size, 1-100, default 20.
- `cursor` — opaque pagination cursor, returned as `next_cursor` when more pages exist.

## Endpoints

### User

- `GET /user/profile` — **Auth required**. Returns `{ id, email, phone, name }`.

### Subscriptions

All subscription endpoints require auth.

- `GET /subscription?language=` — List user's subscriptions. Returns `{ subscriptions: [{ type, publisher?, collection? }] }`.
- `GET /subscription/feed?limit=&language=&cursor=&source_type=&filter_language=` — Paginated subscription feed. `source_type`: `publisher` or `collection`. `filter_language`: filter items with translations in this language. Returns `{ items, next_cursor, has_more }`.
- `POST /subscription/url` with `{ url, type, language }` — Subscribe by URL. `type`: `youtube` or `podcast_show`. Returns `{ publisher_id, status }` or `{ job_id, status }` if async processing needed.
- `POST /subscription/publisher/:uuid` — Subscribe to publisher.
- `DELETE /subscription/publisher/:uuid` — Unsubscribe from publisher.
- `GET /subscription/publisher/:uuid/status` — Returns `{ is_subscribed }`.
- `POST /subscription/collection/:uuid` — Subscribe to collection.
- `DELETE /subscription/collection/:uuid` — Unsubscribe from collection.
- `GET /subscription/collection/:uuid/status` — Returns `{ is_subscribed }`.
- `POST /subscription/publishers/batch` with `{ publisher_ids: [] }` — Batch subscribe (max 50). Returns `{ subscribed_count, failed_ids }`.
- `POST /subscription/targets/batch` with `{ targets: [{ type, id }] }` — Batch subscribe to mixed types (max 50). Returns `{ publishers: { subscribed_count, failed_ids }, collections: { subscribed_count, failed_ids }, total_subscribed }`.
- `POST /subscription/podcast/episode/process` with `{ source: "itunes", feed_url, episode: { episode_url?, title?, published_at?, itunes_track_id? }, language }` — Process a specific podcast episode. At least one episode identifier required. Returns `{ status, item_id?, bootstrap_job_id?, backfill_job_id?, process_job_id? }`.

### Publishers

No authentication required.

- `GET /publishers?limit=&language=&cursor=` — List publishers. Returns `{ publishers: [{ id, type, name, description, avatar, banner }], next_cursor, has_more }`.
- `GET /publishers/:id?language=` — Get publisher detail.
- `GET /publishers/:id/collections?language=` — Get publisher's collections. Returns `{ collections: [...] }`.

### Collections

No authentication required.

- `GET /collections/:id?language=` — Get collection detail. Types: `podcast_show`, `youtube_videos_playlist`, `youtube_shorts_playlist`, `youtube_live_playlist`, `youtube_custom_playlist`.
- `GET /collections/:id/items?limit=&language=&cursor=` — List collection items. Returns `{ items, next_cursor, has_more }`.

### Items

- `POST /items/recommended` with `{ language, limit?, exclude_ids? }` — Personalized recommendations. Auth optional; if unauthenticated, `anon_id` (UUID) is required. Returns `{ items, has_more }`.
- `GET /items/trending?limit=&language=` — Trending items. No auth required. Returns `{ items, has_more }`.
- `GET /items/:id?language=` — Item detail. No auth required. Returns `{ id, name, description, audio_url, published_at, available_languages, banner, provider_ref, item_type, publisher, collection }`.
- `GET /items/:id/similar?language=&limit=` — Similar items (limit 1-20, default 6). No auth required. Returns `{ items }`.
- `GET /items/:id/translation?lang=` — Get full translation document. No auth required. Note: parameter is `lang`, not `language`. Returns `{ schema_version, source: { audio_duration_ms, utterances }, target_language, speakers, units, summary }`.
- `POST /items/:id/process?language=` — **Auth required**. Trigger transcription/translation processing. Consumes ITEM credits.

### Jobs

- `GET /jobs?limit=&status=&language=&cursor=` — **Auth required**. List user's jobs. `status`: comma-separated, values: `pending`, `processing`, `completed`, `failed`. Returns `{ jobs: [{ id, type, status, created_at, item_id?, item?, publisher?, collection? }], next_cursor, has_more }`. Job types: `item_process`, `publisher_subscription`, `podcast_subscription`, `podcast_episode_backfill`.

### Billing

- `GET /billing/credits` — **Auth required**. Returns `{ balances: { ITEM, CHAN }, free_balances: { ITEM, CHAN }, retrieved_at }`. ITEM credits for processing, CHAN credits for subscribing to new channels/shows.

### Bookmarks

All bookmark endpoints require auth.

- `POST /bookmarks/lists` with `{ name, description? }` — Create bookmark list.
- `GET /bookmarks/lists` — List user's bookmark lists.
- `POST /bookmarks/default/items` with `{ item_id, language }` — Add item to default list.
- `POST /bookmarks/lists/:id/items` with `{ item_id }` — Add item to specific list.
- `GET /bookmarks/lists/:id/items?limit=&language=&cursor=` — List items in a bookmark list. Returns `{ items, next_cursor, has_more }`.
- `GET /bookmarks/items/:id/status` — Returns `{ is_bookmarked }`.
- `DELETE /bookmarks/items/:id` — Remove bookmark.

### Recommendations

No authentication required.

- `GET /recommendation/publishers?language=` — Curated publisher groups. Returns `{ groups: [{ id, tagline, publishers }] }`.
- `GET /recommendation/collections?language=` — Curated collection groups. Returns `{ groups: [{ id, tagline, collections }] }`.
