---
title: "Upload audio into a dataset"
method: POST
path: "/api/datasets/{id}/items"
tags: ["Items"]
---

# Upload audio into a dataset

`POST /api/datasets/{id}/items`

## Request

- Base URL: `https://www.audioscrape.com`
- URL: `https://www.audioscrape.com/api/datasets/{id}/items`
- Auth: HTTP bearer

Two intake modes:
  • `Content-Type: multipart/form-data` — form fields `audio` (file), optional `title`, `description`
  • `Content-Type: application/json` — `{ "audio_url": "https://...", "title": "...", "description": "..." }`

JSON mode is the natural fit when the audio is already hosted (S3 presigned URL, CDN, your own server).
Multipart is the natural fit for client-side files (browser uploads, scripts streaming local files).
Both modes converge on the same storage + transcription pipeline; the resulting item is identical.
Transcription minutes consumed count against your plan's monthly quota (see `/api/me/usage`).
After upload, fetch full metadata at `GET /api/items/{item_id}` once transcription completes.

## Constraints

  • **File size:** Free tier is hard-capped at **400 MB** per audio upload regardless of dataset config (**1 GB** for video and for containers intake re-wraps — amr, 3gp, wma, aiff, caf, mpeg — since only the extracted audio is kept). Paid plans honour the dataset's `max_file_size_mb` (default 500 MB). Exceeding the cap returns `413 Payload Too Large`; JSON-mode `audio_url` is fetched under the same cap. (The MCP connector's `transcribe_audio` link path and the web paste-a-link import fetch in the pipeline without a byte cap.)
  • **URL-fetch safety (JSON mode):** `audio_url` must use `https://`. URLs that resolve to private, link-local, loopback, or otherwise internal IP ranges are rejected (SSRF guard) with `422 Unprocessable Entity`.
  • **Dataset configuration:** The target dataset must have `content_type = 'uploads'`. Datasets backed by RSS feeds or other source types return `409 Conflict`.

## Path parameters

- `id` integer, required

## Request body

- UploadFromUrl: JSON body for URL-based upload. Use this when the audio is already hosted somewhere reachable from the public internet (S3 presigned URL, CDN, your own server). Audioscrape downloads it and stores a copy so transcription, indexing, and playback work even if your URL later becomes unavailable.
  - `audio_url` string, required: Publicly reachable `https://` URL of the audio file. Must NOT resolve to a private / internal IP range (SSRF guard).
  - `content_type` string, nullable: What the audio IS (e.g. `phone_call`). Drives the Details panel, speaker-label suggestions, and processing hints. See GH#35.
  - `derive_title` boolean, nullable: GH#617: opt in to derived titles (cleaned filename placeholder + transcript-derived title from the pipeline). Default OFF on the API: the title you send — or the file's own name — is treated as your deliberate choice and never rewritten.
  - `description` string, nullable
  - `metadata` unknown
  - `title` string, nullable

## Response `200`

Upload accepted; item created and queued for transcription

- UploadResponse
  - `duplicate_of` integer, nullable: Set when the bytes matched a recording already in the workspace: nothing was stored or transcribed, no minutes were used, and `item_id` is the existing recording.
  - `item_id` integer, required: ID of the newly-created item. Fetch full metadata at `GET /api/items/{id}`. When `duplicate_of` is set, this is that existing item.
  - `message` string, required: Human-readable status message (e.g. `"queued for transcription"`).
  - `success` boolean, required

## Other responses

- `400`: Validation error — bad URL, missing required multipart field, etc. (`code: VALIDATION_ERROR`)
- `401`: Missing or invalid API key
- `404`: Dataset not found, or caller is not a member of the parent library (returned identically to avoid leaking existence)
- `409`: Dataset exists but is not configured for uploads (`content_type != 'uploads'`)
- `413`: Uploaded / fetched file exceeds the per-upload size cap. Free tier is hard-capped at 400 MB; paid plans use the dataset's `max_file_size_mb` (default 500 MB).
- `415`: Unsupported audio format, or Content-Type is neither `multipart/form-data` nor `application/json`
- `422`: `audio_url` is syntactically valid but unprocessable: DNS failure, non-2xx response, or resolves to a forbidden internal address (SSRF guard)

---

[API](https://skmtc.dev/audioscrape/apis/audioscrape-rest-api.md) · [All operations](https://skmtc.dev/audioscrape/apis/audioscrape-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/audioscrape/apis/audioscrape-rest-api/revisions/29b5788227cf?raw)
