Skip to content
AmplifierDocs
Esc
navigateopen⌘Jpreview
On this page

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:

  1. Call this endpoint to mint a scoped, write-once signed PUT URL.
  2. PUT the audio bytes to upload_url. Send every header in required_headers (not only Content-Type). The PUT targets object storage, not api.amplifierhealth.com.
  3. Call any analyze endpoint with form field audio_upload_ref set to the mint response’s upload_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 0104857600). 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.

Was this page helpful?