Audio API
Endpoints for audio hosting on Picora (v0.12.0+). Audio files share the storage quota with videos and require a paid plan (Pro or Pro+).
Upload Audio
Upload an audio file directly to your library. Unlike videos, audio uploads are synchronous — once the request returns 201, the file is immediately playable.
Endpoint
POST https://api.picora.me/v1/audioAuthentication
Requires Bearer token (API key or JWT access token).
Request
Content-Type: multipart/form-data with fields:
| Field | Type | Required | Description |
|---|---|---|---|
file | file | Yes | Audio file. See accepted MIME types below. |
title | string | No | Display title. Defaults to the filename. Max 255 characters. |
Accepted MIME types & limits
| MIME | Extension | Magic check |
|---|---|---|
audio/mpeg, audio/mp3 | .mp3 | ID3 header or 0xff 0xfb frame sync |
audio/x-m4a, audio/mp4 | .m4a | (container, validated downstream) |
audio/wav, audio/x-wav | .wav | RIFF |
audio/flac | .flac | fLaC |
audio/ogg | .ogg | OggS |
Per-plan limits (also enforced server-side):
| Plan | Max file size | Max duration |
|---|---|---|
| trial | 50 MB | 10 min |
| pro | 100 MB | 1 hour |
| pro+ | 500 MB | 4 hours |
Cover artwork extraction
For MP3 (ID3v2) and FLAC files, Picora parses embedded cover artwork (APIC / PICTURE block) at upload time and stores it as the audio thumbnail. M4A / OGG / WAV files use a default per-format SVG.
bitrate and duration_seconds are populated from the file when parseable; otherwise they remain null.
Example Request
curl -X POST "https://api.picora.me/v1/audio" \ -H "Authorization: Bearer sk_live_YOUR_KEY" \ -F "file=@track.mp3" \ -F "title=Episode 12 — Intro"Response
Status: 201 Created
{ "success": true, "data": { "id": "KkVO6hcQTwBXgPTvb-_uE", "type": "audio", "url": "https://media.picora.me/audio/KkVO6hcQTwBXgPTvb-_uE.mp3", "filename": "track.mp3", "sizeBytes": 5242880, "mimeType": "audio/mpeg", "title": "Episode 12 — Intro", "thumbnailUrl": "https://media.picora.me/audio-cover/KkVO6hcQTwBXgPTvb-_uE.jpg", "durationSeconds": 218, "bitrate": 192, "status": "ready", "isPublic": true, "createdAt": "2026-04-27T08:00:00.000Z" }}Get Audio
Retrieve metadata for a single audio file.
Endpoint
GET https://api.picora.me/v1/audio/:idResponse Fields
| Field | Type | Description |
|---|---|---|
id | string | 21-char nanoid. |
url | string | Public CDN URL. Stable; safe to embed. |
thumbnailUrl | string | Cover image URL — extracted ID3 cover or default SVG. |
durationSeconds | number | null | Track duration (only present for parseable formats). |
bitrate | number | null | kbps. |
status | string | Always ready for audio (no transcoding). |
Update Audio
Patch the title or visibility flag.
Endpoint
PATCH https://api.picora.me/v1/audio/:idBody
{ "title": "New title", "is_public": false }Both fields are optional; sending an empty object is a no-op.
Delete Audio
Permanently delete an audio file. R2 object, embedded cover (if any), database row, and KV cache entry are all removed.
Endpoint
DELETE https://api.picora.me/v1/audio/:idResponse
Status: 204 No Content
Error Responses
| Status | Code | Description |
|---|---|---|
401 | UNAUTHORIZED | Missing or invalid API key. |
403 | FORBIDDEN | Plan does not allow audio (Free), or audio belongs to a different user. |
403 | QUOTA_EXCEEDED | Storage quota exhausted. |
404 | NOT_FOUND | No audio with this ID exists in your library. |
422 | VALIDATION_ERROR | Bad MIME / signature mismatch / oversize. |
429 | RATE_LIMIT | Tiered rate limit hit. See RateLimit-* headers and Retry-After. |
Listing audio
Audio files are returned by the unified media list endpoint with type=audio:
GET https://api.picora.me/v1/media?type=audioSee Media API for full pagination semantics.