Yoto API Findings
Verified findings from direct exploration of the Yoto API: endpoint behaviour, quirks, and implementation notes.
This page documents verified behaviour of the Yoto upstream API based on direct exploration. These findings informed the design of go-yoto and YotoShelf's publishing pipeline. Findings are supplemented by the Yoto developer portal.
API base URLs
| Service | Base URL |
|---|---|
| Auth | https://login.yotoplay.com |
| API | https://api.yotoplay.com |
| Token audience | https://api.yotoplay.com |
Authentication
The Yoto API uses Authorization Code + PKCE. YotoShelf registers a redirect URI at dashboard.yoto.dev.
| Endpoint | Notes |
|---|---|
GET /authorize | Auth Code + PKCE (S256). Params: audience, scope, response_type=code, code_challenge, code_challenge_method=S256. |
POST /oauth/token | Exchange code or refresh. Refresh tokens are single-use — always persist the new token after a refresh. |
GET /userinfo | Returns 401 unless the openid scope is requested. Use GET /user/family to get the account email instead. |
The token exchange returns: access_token, token_type,
expires_in, refresh_token, scope,
id_token, expires_at.
Devices
| Endpoint | Behaviour |
|---|---|
GET /device-v2/devices/mine | Returns {devices: [...]}. Use this — not /devices. |
GET /device-v2/{id}/config |
Returns full device info including a nested status object
with activeCard, batteryLevel, charging,
cardInserted, etc.
|
GET /device-v2/{id}/status | Returns 403 (deprecated). Status is embedded in the config response. |
GET /device-v2/{id}/shortcuts | Returns 403 for read. Write (PUT) works. |
Useful device fields: deviceType (minie/v3e),
deviceFamily (mini/v3),
formFactor (mini/standard),
generation (all current devices return "gen3").
Content library
| Endpoint | Behaviour |
|---|---|
GET /content/mine | Returns ALL cards: MYO, purchased physical, and streaming/podcast. Distinguish by config.onlineOnly and presence of editSettings.rssUrl. |
GET /content/{id}?playable=true&signingType=s3 | Returns time-limited signed S3 URLs for audio. Must be consumed promptly. |
POST /content | Creates or updates a card. Used for both create and update. |
GET /user/family | Returns family info including member emails. Use to obtain the account's display email. |
MYO card structure
A MYO card fetched with ?playable=true&signingType=s3 has this shape:
card: {
cardId, title, slug, sortkey, userId, createdAt, updatedAt, lastCheckedAt
content: {
activity: "yoto_Player"
playbackType: "linear"
restricted: true/false
version: "1"
config: { onlineOnly: false }
chapters: [
{
key, title, overlayLabel, duration, fileSize
availableFrom (optional)
display: { icon16x16: "https://..." }
tracks: [
{
key, title, overlayLabel, duration, fileSize
format: "aac" // MYO cards use aac, not mp3
type: "audio" // vs "stream" for podcasts
trackUrl: "https://s3.amazonaws.com/..." // signed S3 URL
channels (optional)
display: { icon16x16: "..." }
}
]
}
]
}
metadata: { ... }
} Fields not in the original go-yoto types (since fixed)
chapter.availableFromchapter.fileSizetrack.fileSizetrack.channelscard.lastCheckedAt
Cover images
Upload endpoint: POST /media/coverImage/user/me/upload.
The Yoto API calls this a "cover image" — YotoShelf uses the same term.
"Label" refers to the printable sticker output, which is a separate concept.
See Hardware Constraints for dimensions.
Media deduplication
Yoto deduplicates audio server-side by SHA256 hash on upload. Identical audio uploaded to multiple accounts is stored once on Yoto's infrastructure. YotoShelf tracks content hashes locally to enable smart re-publish decisions.
Full card import
YotoShelf can import existing MYO cards from a linked Yoto account:
GET /content/minelists all MYO cards.GET /content/{id}?playable=true&signingType=s3provides signed S3 URLs for audio download.- Cover images are available via
metadata.cover.imageL. - Track icons are available via
chapter.display.icon16x16. - Custom icons are listed at
GET /media/displayIcons/user/me.
Downloaded audio is already transcoded to AAC 128 Kbps (Yoto's re-encode output). Re-uploading would result in a second lossy transcode. YotoShelf marks imported audio as transcoded; users can optionally replace it with original sources.
Rate limiting
No documented rate limit figures from Yoto. YotoShelf applies a 500 ms delay between track operations and exponential backoff on HTTP 429 responses. A weekly CI smoke run is deliberately low-frequency to avoid triggering limits.
Scope reference
Scopes used by YotoShelf:
offline_access, family:devices:*,
family:library:*, user:content:*,
user:icons:*.
The openid scope is not requested by default (see /userinfo note above).
The family:* family admin endpoints return 403 in all configurations tested;
all required data is available via /content/mine and /user/family.