API reference / Content
Media
The media library holds your audio files, MP3 or WAV. Add a file here once,
then send it by its media_id as many times as you like. Add a file from a
public URL in one call, or upload the bytes yourself with a signed upload.
Where you use media
| Where | Field |
|---|---|
Ringless voicemail (POST /rvm) |
media_id |
Voice broadcasts (POST /voice-broadcast) |
media_on_speech, media_on_beep, media_on_transfer, media_on_confirm, media_on_opt_out |
Audio MMS (POST /sms, POST /phone/public/sms/reply) |
media_ids. See MMS. |
| Transcription and voice cloning | media_id, plus ext |
The library stores audio only. To send an image, pass media_urls on the
text instead.
For an audio MMS, the stored file must be 1 MiB or smaller. A voicemail recording is often larger, so export a shorter or lower-bitrate MP3 for MMS.
When you pass a media_id to transcription or voice cloning, also pass the
extension you stored, for example "ext": ".mp3". Without it, .wav is
assumed. See Audio formats.
Routes
| Method | Route | Scope | What it does |
|---|---|---|---|
GET |
/media/public/media |
media:read |
List your playable media |
POST |
/media/public/media |
media:write |
Add media from a URL, or start a signed upload |
POST |
/media/public/media/{media_id}/complete |
media:write |
Finish a signed upload |
GET |
/media/public/media/{media_id}/policy |
media:write |
Get fresh upload URLs |
GET |
/media/public/media/{media_id} |
media:read |
Get one media entry |
PUT |
/media/public/media/{media_id} |
media:write |
Rename or relabel media |
DELETE |
/media/public/media/{media_id} |
media:write |
Delete media |
List media
Returns the media you can send, newest first. An entry waiting for its signed upload to finish isn't listed.
| Field | Type | Required | Description |
|---|---|---|---|
skip |
integer | No | Entries to skip. Default 0. |
limit |
integer | No | Page size. Default 100. |
curl "https://api-v2.dropcowboy.com/media/public/media?limit=10" \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"
{
"data": {
"medias": [
{
"team_id": "cd5cd773-4617-4b28-854d-d3adc74c96d5",
"media_id": "0786a81e-e11e-4e53-ab64-71f552db23b3",
"name": "September promo",
"created_at": 1757491200000,
"approved_at": 1757491200000,
"api_allowed": true
}
],
"total": 1
},
"meta": { "request_id": "88f84098-c512-4585-9fd7-0d8bc8400944" }
}
data.total counts every playable entry, not just this page. Page with
skip until you've read total entries. Timestamps are epoch milliseconds.
Create media
Send JSON with either url or signed_upload: true. The response is 201.
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Display name. |
type |
string | No | Your own label, for example rvm. |
url |
string | One of url or signed_upload |
Public URL of an MP3 or WAV file. |
ext |
string | No | With url: the file's format, .wav (default) or .mp3. |
signed_upload |
boolean | One of url or signed_upload |
true to get signed URLs and upload the bytes yourself. |
From a URL
We download the file while you wait. It must be 50 MiB or smaller and download within 15 seconds. When the call returns, the media is ready to send.
curl -X POST https://api-v2.dropcowboy.com/media/public/media \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
-H "Content-Type: application/json" \
-d '{
"name": "October follow-up",
"type": "rvm",
"url": "https://files.example.com/october-follow-up.mp3",
"ext": ".mp3"
}'
{
"data": {
"media_id": "55b9e55e-23f1-4c16-8865-f4b6261ebeea",
"name": "October follow-up",
"type": "rvm",
"media_exists": true,
"approved_at": 1759312800000,
"api_allowed": true
},
"meta": { "request_id": "3028a01c-9f13-4158-a864-2daa70189301" }
}
If the download fails, no media is saved. Fix the URL and call again.
Signed upload
Use this when the file is on your own server rather than at a public URL.
- Create the entry with
signed_upload: true. The response hasupload.mp3andupload.wav, each with a signedurland thecontent_typeto send. PUTthe file to the URL for its format, with exactly thatContent-Type. The URLs are valid for 2 days.- Call Complete a signed upload. Until you do,
the entry has
media_exists: falseand can't be sent.
curl -X POST https://api-v2.dropcowboy.com/media/public/media \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
-H "Content-Type: application/json" \
-d '{ "name": "October follow-up", "type": "rvm", "signed_upload": true }'
{
"data": {
"media_id": "55b9e55e-23f1-4c16-8865-f4b6261ebeea",
"name": "October follow-up",
"type": "rvm",
"signed_upload": true,
"media_exists": false,
"api_allowed": false,
"upload": {
"mp3": { "url": "https://uploads.example.com/55b9e55e-23f1-4c16-8865-f4b6261ebeea.mp3?X-Amz-Signature=...", "content_type": "audio/mpeg" },
"wav": { "url": "https://uploads.example.com/55b9e55e-23f1-4c16-8865-f4b6261ebeea.wav?X-Amz-Signature=...", "content_type": "audio/wav" }
}
},
"meta": { "request_id": "50bb4bbb-3f86-459a-9761-f8bd7ff12f1b" }
}
curl -X PUT "$UPLOAD_MP3_URL" \
-H "Content-Type: audio/mpeg" \
--data-binary @october-follow-up.mp3
Complete a signed upload
Call this after your PUT succeeds. The media is then ready to send.
curl -X POST https://api-v2.dropcowboy.com/media/public/media/55b9e55e-23f1-4c16-8865-f4b6261ebeea/complete \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"
{
"data": {
"media_id": "55b9e55e-23f1-4c16-8865-f4b6261ebeea",
"media_exists": true,
"approved_at": 1759313100000,
"api_allowed": true
},
"meta": { "request_id": "764ff1bd-86e1-49af-8703-2ad22b53f04a" }
}
Refresh upload URLs
Returns new signed upload URLs for an entry, in the same mp3 and wav
shape as upload. Call it when a PUT is rejected because the URL expired.
curl https://api-v2.dropcowboy.com/media/public/media/55b9e55e-23f1-4c16-8865-f4b6261ebeea/policy \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"
{
"data": {
"mp3": { "url": "https://uploads.example.com/55b9e55e-23f1-4c16-8865-f4b6261ebeea.mp3?X-Amz-Signature=...", "content_type": "audio/mpeg" },
"wav": { "url": "https://uploads.example.com/55b9e55e-23f1-4c16-8865-f4b6261ebeea.wav?X-Amz-Signature=...", "content_type": "audio/wav" }
},
"meta": { "request_id": "e2db9755-0c26-4aae-823a-dfb1b7c05acf" }
}
Get media
curl https://api-v2.dropcowboy.com/media/public/media/55b9e55e-23f1-4c16-8865-f4b6261ebeea \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"
{
"data": {
"_id": "66f2b1c4e8a9d3f1a2b4c6d8",
"team_id": "cd5cd773-4617-4b28-854d-d3adc74c96d5",
"media_id": "55b9e55e-23f1-4c16-8865-f4b6261ebeea",
"media_exists": true,
"name": "October follow-up",
"type": "rvm",
"src_url": "https://files.example.com/october-follow-up.mp3",
"created_at": 1759312800000,
"created_by": "fa933d82-485f-43b0-80ab-860121f06980",
"modified_at": null,
"modified_by": null,
"deleted_at": null,
"deleted_by": null,
"approved_at": 1759312800000
},
"meta": { "request_id": "787d0f0b-aa13-4ce9-890c-202d68b72467" }
}
A deleted entry returns 404, so a media_id you stored earlier is safe to
send only if this call still finds it.
Update media
Changes the name or type. The audio can't be replaced: create new media
instead.
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | No | New display name. |
type |
string | No | New label. |
curl -X PUT https://api-v2.dropcowboy.com/media/public/media/55b9e55e-23f1-4c16-8865-f4b6261ebeea \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
-H "Content-Type: application/json" \
-d '{ "name": "October follow-up v2" }'
{
"data": {
"team_id": "cd5cd773-4617-4b28-854d-d3adc74c96d5",
"media_id": "55b9e55e-23f1-4c16-8865-f4b6261ebeea",
"modified_at": 1759399200000,
"modified_by": "fa933d82-485f-43b0-80ab-860121f06980",
"name": "October follow-up v2"
},
"meta": { "request_id": "c6e0e173-ab7e-45d6-b470-72d593b15f56" }
}
The response echoes the change even when the media_id doesn't exist. To
confirm an entry exists, get it first.
Delete media
Removes the entry from your library. Messages already sent aren't affected.
curl -X DELETE https://api-v2.dropcowboy.com/media/public/media/55b9e55e-23f1-4c16-8865-f4b6261ebeea \
-H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"
{
"data": { "deleted": true },
"meta": { "request_id": "964c9795-8bdd-475a-917a-2ec2727c2cfb" }
}
Errors
| Status | When | What to do |
|---|---|---|
400 |
The url isn't a public http or https address. |
Host the file somewhere reachable from the internet. |
413 |
The file at url is larger than 50 MiB. |
Export a smaller file. |
502 |
The server at url returned an error or closed the connection. |
Open the URL yourself to check it, then call again. |
504 |
The file didn't download within 15 seconds. | Use faster hosting, or a signed upload. |
400 |
On complete: Upload not found. PUT audio to the signed URL first. |
Upload the file to a signed URL, then complete. If the URL expired, refresh it. |
404 |
The media_id isn't on your account, or was deleted. |
Check the id with List media. |
Sends that use media report their own outcomes. 3033 (Media Not Found) means
the media_id was deleted, belongs to another account, or its upload was never
completed. 3035 (Media Too Large) means the file is over the MMS size limit.
See Outcomes for both. For every other error, see
Responses, errors and limits.