# Yoto API Findings

Verified findings from direct exploration of the Yoto upstream API. This is living documentation — it is updated when the weekly smoke test detects upstream changes.

## Endpoint overview

The Yoto API is undocumented and unofficial. These findings come from network inspection, go-yoto's integration test harness, and the `yoto-explorer` tool.

Base URL: `https://api.yotoplay.com`

Authentication: OAuth2 Authorization Code + PKCE. Client ID is publicly available from the Yoto mobile apps.

## Undocumented quirks

### Device status embedded in config

`GET /device-v2/{id}/status` returns HTTP 403. Device status — active card ID, battery level, charging state, sleep state — is embedded inside the device config response at `GET /device-v2/{id}/config`.

### Single-use refresh tokens

Yoto refresh tokens are single-use. Each token exchange returns a new refresh token that replaces the previous one. If you discard the new refresh token (e.g., crash between receiving it and persisting it), you are locked out and must re-authenticate.

YotoShelf persists the new token atomically in a database transaction before considering the exchange complete.

### userinfo scope not in default

The OIDC `/userinfo` endpoint requires the `openid` scope, which is not in the default scope set returned during OAuth2. The standard approach of fetching the user email from `/userinfo` does not work without requesting this scope explicitly.

Workaround: call `GET /user/family` instead. The primary account email is at `family.Members[0].Email`.

## MYO card structure

MYO (Make Your Own) cards appear in `GET /content/mine` alongside purchased and streaming cards. Distinguish them:

| Type | `config.OnlineOnly` | `editSettings.RssUrl` | Track type |
|---|---|---|---|
| MYO / purchased | `false` or absent | absent | `"audio"` |
| Streaming / podcast | `true` | present | `"stream"` |

Track audio is served as signed S3 URLs (AAC format). Request with `GetCardPlayable` to get valid signed URLs.

## Import feasibility

Importing existing MYO cards from a Yoto account into YotoShelf is feasible:

- Metadata (title, cover URL, track list, chapter icons) is available from the content API.
- Audio files are served as signed S3 URLs and can be downloaded.
- Cover images are served as CDN URLs and can be downloaded.
- Chapter icons (display icons) are served as CDN URLs.

YotoShelf's import feature (`POST /api/import`) uses this flow.

## Pagination

Content list endpoints (`/content/mine`) return all cards in a single response — there is no server-side pagination. For large libraries this can be a slow response. Client-side pagination is applied by YotoShelf.

## Rate limits

Rate limits are not documented. In practice, the API handles several requests per second without issue. The `go-yoto` client includes exponential backoff on `429` responses.
