Home → Blog → Speech to text in Java: code on the standard HttpClient
Speech to text in Java: code on the standard HttpClient
Java has shipped an HTTP client since version 11, and that is all you need — no third-party libraries for uploading audio. The one annoyance is assembling the multipart body by hand. Here is code you can paste.
Building the multipart request
import java.net.URI;
import java.net.http.*;
import java.nio.file.*;
import java.io.ByteArrayOutputStream;
String boundary = "----vs" + System.nanoTime();
Path audio = Path.of("call.ogg");
var body = new ByteArrayOutputStream();
body.write(("--" + boundary + "\r\n"
+ "Content-Disposition: form-data; name=\"model\"\r\n\r\nwhisper-1\r\n"
+ "--" + boundary + "\r\n"
+ "Content-Disposition: form-data; name=\"file\"; filename=\"" + audio.getFileName() + "\"\r\n"
+ "Content-Type: audio/ogg\r\n\r\n").getBytes());
body.write(Files.readAllBytes(audio));
body.write(("\r\n--" + boundary + "--\r\n").getBytes());
var request = HttpRequest.newBuilder(URI.create("https://voicesscribe.com/v1/audio/transcriptions"))
.header("Authorization", "Bearer " + System.getenv("VS_KEY"))
.header("Content-Type", "multipart/form-data; boundary=" + boundary)
.timeout(java.time.Duration.ofMinutes(3))
.POST(HttpRequest.BodyPublishers.ofByteArray(body.toByteArray()))
.build();
var client = HttpClient.newHttpClient();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new IllegalStateException("error " + response.statusCode() + ": " + response.body());
}
System.out.println(response.body());
The line breaks in the boundaries must be carriage return plus line feed: with a bare newline the server cannot parse the body.
Parsing the response
The response is JSON with a text field. Any familiar parser will do — Jackson, Gson or your framework's built-in support:
record Transcription(String text) {}
var mapper = new com.fasterxml.jackson.databind.ObjectMapper();
var result = mapper.readValue(response.body(), Transcription.class);
System.out.println(result.text());
If you requested srt or vtt, the response is not JSON at all but a ready subtitle file — nothing to parse.
Under load
Three things worth doing from the start:
- Keep one HttpClient per application — it is thread-safe and reuses connections.
- Do not read large files fully into memory: BodyPublishers.ofFile streams them.
- Bound concurrency with a fixed thread pool sized to your plan's rate limit.
Common failures
| Symptom | Cause |
|---|---|
| 400 on a valid file | missing filename in the form part or a broken boundary |
| 401 | the key never made it out of the environment variable |
| 413 | file above 25 MB — compress or split |
| Cut off on long files | no timeout set on the request |
Try it on your own recordings. Sign-up takes a minute, and the free minutes are enough to judge the quality.
Get a free API keyFrequently asked questions
Do I need OkHttp or Apache HttpClient?
Not necessarily: the built-in client is enough. OkHttp is nicer in that it assembles multipart bodies for you.
Does this work on Java 8?
No, the built-in HttpClient arrived in Java 11. On 8 use OkHttp or Apache HttpClient.
How do I pass the audio language?
Add another form part named language with a code such as en.
Can I stream the file instead of buffering?
Yes, BodyPublishers.ofFile sends it without loading it into memory, which matters for files near the size limit.
Related reading
- Speech to text in C#: connecting from .NET in five minutes — How to transcribe audio from C#: the official client and a plain HttpClient version, async processing, timeouts and error handling in a .NET service.
- Speech to text in Go: working code on the standard library — How to send audio for transcription from Go: a multipart request on the standard library, response parsing, timeouts, retries and a worker pool for archives.
- Transcription API errors and what they actually mean — A walkthrough of transcription API status codes: why 401, 400, 413, 429 and 502 happen, how to fix each one and which failures are worth retrying.