New: Import recordings from Google Drive, OneDrive, Zoom, Dropbox & Box. First 3 imports free.

Import a recording
Pepys

API & MCP

Direct uploads

Three calls: ask for a presigned URL, PUT the bytes, then transcribe the reference you got back.

In short

For a file on your own machine, POST /api/v1/uploads with its filename, content type, and byte size. The response carries a presigned upload_url, a media_ref, and an expiry. PUT the bytes to that URL with a matching Content-Type and Content-Length, then pass the media_ref to the transcriptions endpoint.

The handshake

The handshake tells Pepys what is coming so it can authorise a one-off upload URL. Send the filename, the content type, and the exact byte size; the response returns the URL to PUT to, the media_ref that identifies the file afterwards, and how long the URL stays valid.

1. handshake
curl -X POST https://pepys.co/api/v1/uploads \
  -H "Authorization: Bearer pk_live_…" \
  -d '{ "filename": "call.mp3", "content_type": "audio/mpeg", "bytes": 5242880 }'
# → { "upload_url": "https://…", "media_ref": "uploads/<you>/<uuid>.mp3", "expires_in": 600 }

Upload the bytes

PUT the file to the presigned URL. The Content-Type and Content-Length must match what you declared in the handshake – a mismatch is rejected, since the URL was authorised for that exact size and type.

2. upload
curl -X PUT "<upload_url>" -H "Content-Type: audio/mpeg" --data-binary @call.mp3

Transcribe the upload

Pass the media_ref as the source of a transcription job. From there it behaves like any other job: poll Get a transcription or wait for a webhook.

3. transcribe it
curl -X POST https://pepys.co/api/v1/transcriptions \
  -H "Authorization: Bearer pk_live_…" \
  -d '{ "media_ref": "uploads/<you>/<uuid>.mp3" }'

Direct uploads – questions, answered

When should I use a direct upload instead of a url?

When the file is on your own machine or private network and has no public URL. The upload flow hands Pepys the bytes through a presigned URL instead.

How long is the presigned upload URL valid?

The handshake response includes expires_in, currently 600 seconds. Request a fresh URL if yours lapses.

Why was my PUT rejected?

The Content-Type and Content-Length you send must match what the handshake declared. The URL is authorised for that exact type and size.

What do I do with the media_ref?

Pass it as the source of POST /api/v1/transcriptions. The job then runs and reports back like any other transcription.

Related

Try it on your own audio

Create a free account and transcribe a recording – 60 minutes are included, no card required. Still stuck? Email contact@pepys.co or see the support page.