# Upload Audio

`POST /v1/audio`

Upload a short audio clip for lip-sync and audio-guided video. The clip is transcribed and screened before it can be used.

The one place every account can send media from outside. Send a WAV or MP3 of 2 to 30 seconds, up to 15 MB, either as a multipart `file` or as a JSON `{ "url" }` we download from a public https address. The format and duration are read from the bytes; the declared content type is ignored.
Every clip is transcribed and the transcript goes through the same screen as a prompt. Flat charge of $0.01 per upload for that screening. A clip that fails the screen is discarded and returns the same 422 shape as a blocked prompt (`code`, `outcome`, `categories`); the $0.01 still applies. When transcription or the screen is unreachable the upload returns 503, nothing is stored and the charge is refunded: retry in a few seconds.
The returned `url` is what you pass as `audio_url` or in `audio_urls` on `POST /v1/videos/generations`. Clips uploaded by another account, or any external audio URL, are rejected there before you are charged. Sandbox keys get a fixture clip and pay nothing.

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

## Authorizations

- `Authorization` (string, header, required): Bearer authentication header of the form `Bearer <token>`, where `<token>` is your SpicyAPI key (`sk-spicy-…`). Create one in the dashboard under API Keys.

## Body (multipart/form-data)

Send exactly one of `file` (multipart/form-data) or `url` (an `application/json` body).

- `file` (binary, multipart, optional): The audio file. WAV or MP3, 2 to 30 seconds, at most 15 MB.
- `url` (string, json, optional): Public https URL of a WAV or MP3 we fetch on your behalf (same size and length limits; private, loopback and plain-IP hosts are refused).
- `user` (string, optional): Your own id for the end user making this request (up to 128 characters, hashed at rest). Send it if your product serves many people: declined-prompt history, strikes and suspensions are then kept per end user, so one person's behaviour never affects another's requests or your account. After 10 severe violations that user gets `403 end_user_suspended`; the id is echoed back as `user` in every screening error so you can act on it.

## Request

```bash
curl --request POST \
  --url https://api.spicyapi.com/v1/audio \
  --header 'Authorization: Bearer $SPICYAPI_KEY' \
  --form 'file=@line.wav'

# or from a public URL
curl --request POST \
  --url https://api.spicyapi.com/v1/audio \
  --header 'Authorization: Bearer $SPICYAPI_KEY' \
  --header 'Content-Type: application/json' \
  --data '{ "url": "https://example.com/line.mp3" }'
```

## Response: 200 application/json

Audio

- `id` (string, required): Clip id, `au_...`.
- `object` (string, required): Always `audio`.
- `url` (string, required): CDN URL of the clip. Pass it byte-for-byte as `audio_url` (or in `audio_urls`) on `POST /v1/videos/generations`.
- `duration_s` (number, required): Length in seconds, to one decimal.
- `mime` (string, required): `audio/wav` or `audio/mpeg`, sniffed from the bytes.
- `bytes` (integer, required): File size.
- `transcript` (string, required): What the screen heard (first 500 characters).
- `source` (string, required): `upload` for `POST /v1/audio`, `speech` for `POST /v1/audio/speech`.
- `created` (integer | null, optional): Unix timestamp.
- `cost_usd` (number, required): Always 0.01 (the screening charge); 0 on a sandbox key.

```json
{
  "id": "au_3c9f1e7a2b4d6f80a1c2",
  "object": "audio",
  "url": "https://cdn.spicyapi.com/audio/a1b2c3d4e5f6a7b8/au_3c9f1e7a2b4d6f80a1c2.wav",
  "duration_s": 6.4,
  "mime": "audio/wav",
  "bytes": 1128492,
  "transcript": "Come here. I have been waiting all evening.",
  "source": "upload",
  "created": 1758553200,
  "cost_usd": 0.01
}
```
