Audio Uploads
Mint a signed PUT URL and analyze with audio_upload_ref.
Use POST /v2/audio/uploads when you have a local audio file and do not want to send the bytes as multipart/form-data on the analyze call.
The flow is:
- Call this endpoint to mint a scoped, write-once signed PUT URL.
PUTthe audio bytes toupload_url. Send every header inrequired_headers(not onlyContent-Type). The PUT targets object storage, notapi.amplifierhealth.com.- Call any analyze endpoint with form field
audio_upload_refset to the mint response’supload_ref.
Provide either audio or audio_upload_ref on analyze — not both. See Model API, Sign API, and Longitudinal API.
Mint an upload URL
POST /v2/audio/uploads
Mint a signed upload URL for a direct-to-storage PUT.
Requests use Content-Type: application/json.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
content_type |
string | Yes | MIME type of the file you will PUT (for example audio/wav, audio/flac, audio/mpeg, audio/mp4). The Content-Type on the PUT must match this value and the Content-Type entry in required_headers. |
filename |
string or null | No | Original filename. Optional metadata for the upload; it is not a path on Amplifier. |
Response
| Field | Type | Description |
|---|---|---|
upload_url |
string | Signed PUT URL. Write the audio bytes here once before expires_at. |
upload_ref |
string | Opaque reference. Pass this value as audio_upload_ref on the analyze request. |
expires_at |
string | ISO 8601 time after which upload_url is no longer valid. |
required_headers |
object | Headers that must be sent on the PUT, including Content-Type and X-Goog-Content-Length-Range. Copy them as returned. Omitting a signed header makes storage reject the PUT (MalformedSecurityHeader). |
The analyze form field is named audio_upload_ref. The mint field is named upload_ref. Use the mint value in the analyze field.
Example response
{
"upload_url": "https://storage.googleapis.com/example-bucket/example-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-SignedHeaders=content-type%3Bhost%3Bx-goog-content-length-range&...",
"upload_ref": "YjVkMmJiNTQ2YWZmNGE0ZGIzNGIxYzAwNmViMjA3ZjQ6d2F2",
"expires_at": "2026-09-10T12:43:58.097178+00:00",
"required_headers": {
"Content-Type": "audio/wav",
"X-Goog-Content-Length-Range": "0,104857600"
}
}
X-Goog-Content-Length-Range is the byte range GCS will accept for this object (here 0–104857600). Amplifier still enforces the audio size and duration limits when the job is analyzed.
Example
Mint, PUT, then analyze. Copy upload_url and upload_ref from the mint JSON. On the PUT, send every required_headers pair — for the example response above, that is Content-Type and X-Goog-Content-Length-Range.
curl -X POST https://api.amplifierhealth.com/v2/audio/uploads \
-H "X-Account-ID: your-account-id" \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{"content_type":"audio/wav","filename":"recording.wav"}'
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: audio/wav" \
-H "x-goog-content-length-range: 0,104857600" \
--data-binary @recording.wav
curl -X POST https://api.amplifierhealth.com/v2/models/pulse/analyze \
-H "X-Account-ID: your-account-id" \
-H "X-API-Key: your-api-key" \
-F "audio_upload_ref=$UPLOAD_REF"const fs = require("fs");
const mint = await fetch("https://api.amplifierhealth.com/v2/audio/uploads", {
method: "POST",
headers: {
"X-Account-ID": process.env.AMPLIFIER_ACCOUNT_ID,
"X-API-Key": process.env.AMPLIFIER_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
content_type: "audio/wav",
filename: "recording.wav",
}),
});
const { upload_url, upload_ref, required_headers } = await mint.json();
await fetch(upload_url, {
method: "PUT",
headers: required_headers,
body: fs.readFileSync("recording.wav"),
});
const form = new FormData();
form.append("audio_upload_ref", upload_ref);
const response = await fetch("https://api.amplifierhealth.com/v2/models/pulse/analyze", {
method: "POST",
headers: {
"X-Account-ID": process.env.AMPLIFIER_ACCOUNT_ID,
"X-API-Key": process.env.AMPLIFIER_API_KEY,
},
body: form,
});
const data = await response.json();# Requires httpx: pip install httpx
import os
import httpx
headers = {
"X-Account-ID": os.environ["AMPLIFIER_ACCOUNT_ID"],
"X-API-Key": os.environ["AMPLIFIER_API_KEY"],
}
mint = httpx.post(
"https://api.amplifierhealth.com/v2/audio/uploads",
headers=headers,
json={"content_type": "audio/wav", "filename": "recording.wav"},
)
payload = mint.json()
with open("recording.wav", "rb") as f:
httpx.put(
payload["upload_url"],
headers=payload["required_headers"],
content=f.read(),
)
response = httpx.post(
"https://api.amplifierhealth.com/v2/models/pulse/analyze",
headers=headers,
data={"audio_upload_ref": payload["upload_ref"]},
)
data = response.json()If the PUT omits X-Goog-Content-Length-Range (or any other name listed in required_headers / X-Goog-SignedHeaders), storage returns XML MalformedSecurityHeader and analyze fails with Invalid audio_upload_ref.
Errors
For 401 and other Amplifier codes, see Errors. A 422 response is a request-validation error (for example a missing content_type). After a failed PUT, analyze returns 400 with INVALID_REQUEST / Invalid audio_upload_ref.
Related pages
- Model API — analyze with
audiooraudio_upload_ref. - Sign API — same audio fields on a single sign.
- Longitudinal API — analyze into a group with
audiooraudio_upload_ref. - Audio Requirements — formats, size, and duration.