NativePort
← Speech to text API

Turn an interview or meeting into a transcript

Upload a recording and get its text with word timestamps and speaker labels. This guide uses ElevenLabs and shows how to format the result into speaking turns.

Try a request

curl
curl https://api.nativeport.ai/elevenlabs/v1/speech-to-text \
  -H "Authorization: Bearer $NATIVEPORT_API_KEY" \
  -F "[email protected]" \
  -F "model_id=scribe_v1" \
  -F "diarize=true"
example response
{
  "language_code": "en",
  "language_probability": 0.98,
  "text": "So the first thing we changed was the billing model. Right, and that took how long?",
  "words": [
    {"text": "So", "start": 0.12, "end": 0.28, "speaker_id": "speaker_0"},
    {"text": "the", "start": 0.28, "end": 0.39, "speaker_id": "speaker_0"}
  ]
}

Read the transcript and speaker turns

Upload the recording as multipart form data, using a field named file. The curl example uses -F for the file and transcription options. The Python example builds the same multipart request using the standard library.

The response includes text for the complete transcript and a words list with start and end times. When you request diarization, the word entries also include speaker IDs. Group those entries into speaking turns for a transcript, or use the timestamps to link text back to the audio.

Choose the fields your app needs. A summary workflow may use the complete text, while an interview viewer may need both speaker turns and timing.

Before processing a collection, compare the cost for its recording lengths. NativePort’s ElevenLabs route uses a flat approximation per call; Fish Audio transcription uses a per-second rate. At the current example rates in the transcription overview, short clips cost less on Fish Audio and longer single requests cost less on ElevenLabs.

Format a transcript into speaker turns

Groups consecutive words by speaker ID and prints each speaking turn on its own line.

python
import json, os, sys, urllib.request, uuid

def post_audio(path):
    boundary = uuid.uuid4().hex
    fields = {"model_id": "scribe_v1", "diarize": "true"}
    body = b""
    for k, v in fields.items():
        body += (f"--{boundary}\r\nContent-Disposition: form-data; "
                 f'name="{k}"\r\n\r\n{v}\r\n').encode()
    body += (f"--{boundary}\r\nContent-Disposition: form-data; "
             f'name="file"; filename="{os.path.basename(path)}"\r\n'
             f"Content-Type: application/octet-stream\r\n\r\n").encode()
    body += open(path, "rb").read() + f"\r\n--{boundary}--\r\n".encode()

    req = urllib.request.Request(
        "https://api.nativeport.ai/elevenlabs/v1/speech-to-text",
        data=body,
        headers={
            "Authorization": f"Bearer {os.environ['NATIVEPORT_API_KEY']}",
            "Content-Type": f"multipart/form-data; boundary={boundary}",
        },
    )
    with urllib.request.urlopen(req) as r:
        return json.load(r)

res = post_audio(sys.argv[1])

turn, speaker = [], None
for w in res.get("words", []):
    if w.get("speaker_id") != speaker:
        if turn:
            print(f"{speaker}: {' '.join(turn)}")
        speaker, turn = w.get("speaker_id"), []
    turn.append(w["text"])
if turn:
    print(f"{speaker}: {' '.join(turn)}")
example output
$ python transcribe.py interview.mp3
speaker_0: So the first thing we changed was the billing model.
speaker_1: Right, and that took how long?

Consider another approach

For speaker labels and word timestamps

ElevenLabs Scribe includes word timing and, when requested, speaker IDs in the transcription response.

For another transcription option

Fish Audio's ASR route is billed per second of audio. Compare its output and the cost for your recording length with the ElevenLabs example.

Use it with NativePort

Transcribe with ElevenLabs or try Fish Audio through the same NativePort account. Your balance can also cover a model that summarizes the transcript afterwards.

Before you start

How do I separate the speakers?

Set diarize=true in the ElevenLabs request. Group consecutive words by speaker_id to create speaking turns, as the Python example does. Speaker IDs distinguish voices, so add names separately if you know who is speaking.

Which provider costs less for my recording?

ElevenLabs uses a flat approximation per request through NativePort. Fish Audio transcription is billed per second. Multiply the audio duration by the per-second rate and compare that with the flat price, accounting for any splitting your files need. Current prices are on the provider pages.

Does it detect the language?

The response includes a detected language_code and language_probability. Use that confidence value to identify results you may want to review against the recording.

What files can I use?

Common formats include MP3, WAV, M4A, and FLAC. Check the provider documentation for current format and size limits. Test with audio similar to the recordings your users will submit.