PDF to EPUB Conversion in Java — toolkit.bot API Integration
This guide shows how to call the toolkit.bot REST API from Java to convert PDF files to EPUB. The API uses multipart form upload and an async job model — upload a file, poll for completion, download the result.
All examples use standard Java libraries. No third-party PDF library required.
Prerequisites
- Java 11 or later (for
java.net.http.HttpClient) - A toolkit.bot API key — get one free at toolkit.bot/api
- Maven or Gradle for dependency management (OkHttp example only)
Java 11+ HttpClient — no dependencies
import java.net.URI;
import java.net.http.*;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.file.*;
import java.util.concurrent.TimeUnit;
public class Pdf2EpubClient {
private static final String API_BASE = "https://toolkit.bot/api/v1";
private static final String API_KEY = System.getenv("TOOLKIT_API_KEY");
public static void main(String[] args) throws Exception {
Path pdfPath = Path.of("document.pdf");
Path epubPath = Path.of("document.epub");
convertPdfToEpub(pdfPath, epubPath);
}
static void convertPdfToEpub(Path pdf, Path output) throws Exception {
HttpClient client = HttpClient.newHttpClient();
String boundary = "----JavaBoundary" + System.currentTimeMillis();
// Build multipart body
byte[] fileBytes = Files.readAllBytes(pdf);
String header = "--" + boundary + "
"
+ "Content-Disposition: form-data; name="file"; filename=""
+ pdf.getFileName() + ""
"
+ "Content-Type: application/pdf
";
String footer = "
--" + boundary + "--
";
byte[] body = concat(header.getBytes(), fileBytes, footer.getBytes());
HttpRequest uploadReq = HttpRequest.newBuilder()
.uri(URI.create(API_BASE + "/jobs"))
.header("Authorization", "Bearer " + API_KEY)
.header("Content-Type", "multipart/form-data; boundary=" + boundary)
.POST(BodyPublishers.ofByteArray(body))
.build();
HttpResponse<String> uploadResp = client.send(uploadReq, BodyHandlers.ofString());
if (uploadResp.statusCode() != 202) {
throw new RuntimeException("Upload failed: " + uploadResp.body());
}
// Parse job ID (simple JSON extraction)
String respBody = uploadResp.body();
String jobId = respBody.replaceAll(".*"job_id":\s*"([^"]+)".*", "$1");
System.out.println("Job ID: " + jobId);
// Poll for completion
String downloadUrl = null;
for (int i = 0; i < 60; i++) {
TimeUnit.SECONDS.sleep(3);
HttpRequest statusReq = HttpRequest.newBuilder()
.uri(URI.create(API_BASE + "/jobs/" + jobId))
.header("Authorization", "Bearer " + API_KEY)
.GET()
.build();
HttpResponse<String> statusResp = client.send(statusReq, BodyHandlers.ofString());
String status = statusResp.body();
System.out.println("Status: " + status.substring(0, Math.min(120, status.length())));
if (status.contains(""status":"done"")) {
downloadUrl = status.replaceAll(".*"download_url":\s*"([^"]+)".*", "$1");
break;
}
if (status.contains(""status":"failed"")) {
throw new RuntimeException("Conversion failed: " + status);
}
}
if (downloadUrl == null) throw new RuntimeException("Timed out waiting for job");
// Download EPUB
HttpRequest dlReq = HttpRequest.newBuilder()
.uri(URI.create(downloadUrl))
.header("Authorization", "Bearer " + API_KEY)
.GET()
.build();
HttpResponse<Path> dlResp = client.send(dlReq, BodyHandlers.ofFile(output));
System.out.println("Saved to: " + dlResp.body());
}
static byte[] concat(byte[]... arrays) {
int total = 0;
for (byte[] a : arrays) total += a.length;
byte[] result = new byte[total];
int pos = 0;
for (byte[] a : arrays) {
System.arraycopy(a, 0, result, pos, a.length);
pos += a.length;
}
return result;
}
}
OkHttp example
If you prefer OkHttp (already in your stack via Retrofit or another library), add the dependency:
<!-- Maven -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
import okhttp3.*;
import java.io.*;
import java.nio.file.*;
import java.util.concurrent.TimeUnit;
public class Pdf2EpubOkHttp {
private static final String API_BASE = "https://toolkit.bot/api/v1";
private static final String API_KEY = System.getenv("TOOLKIT_API_KEY");
public static void main(String[] args) throws Exception {
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(30, TimeUnit.SECONDS)
.build();
File pdfFile = new File("document.pdf");
RequestBody fileBody = RequestBody.create(pdfFile, MediaType.get("application/pdf"));
RequestBody multipart = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", pdfFile.getName(), fileBody)
.build();
Request uploadReq = new Request.Builder()
.url(API_BASE + "/jobs")
.header("Authorization", "Bearer " + API_KEY)
.post(multipart)
.build();
String jobId;
try (Response resp = client.newCall(uploadReq).execute()) {
String body = resp.body().string();
jobId = body.replaceAll(".*"job_id":\s*"([^"]+)".*", "$1");
System.out.println("Job: " + jobId);
}
// Poll
String downloadUrl = null;
for (int i = 0; i < 60; i++) {
Thread.sleep(3000);
Request statusReq = new Request.Builder()
.url(API_BASE + "/jobs/" + jobId)
.header("Authorization", "Bearer " + API_KEY)
.get().build();
try (Response resp = client.newCall(statusReq).execute()) {
String body = resp.body().string();
if (body.contains(""done"")) {
downloadUrl = body.replaceAll(
".*"download_url":\s*"([^"]+)".*", "$1");
break;
}
}
}
// Download
Request dlReq = new Request.Builder()
.url(downloadUrl)
.header("Authorization", "Bearer " + API_KEY)
.get().build();
try (Response resp = client.newCall(dlReq).execute()) {
Files.write(Path.of("document.epub"), resp.body().bytes());
}
System.out.println("Done: document.epub");
}
}
Spring Boot integration
For Spring Boot applications, inject a configured RestTemplate or WebClient and wrap the conversion in a @Service:
@Service
public class EpubConversionService {
@Value("${toolkit.api.key}")
private String apiKey;
private final RestTemplate rest = new RestTemplate();
private static final String API = "https://toolkit.bot/api/v1";
public Path convertPdfToEpub(MultipartFile file) throws Exception {
// Upload
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(apiKey);
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", new ByteArrayResource(file.getBytes()) {
@Override public String getFilename() { return file.getOriginalFilename(); }
});
ResponseEntity<Map> resp = rest.exchange(
API + "/jobs", HttpMethod.POST,
new HttpEntity<>(body, headers), Map.class);
String jobId = (String) resp.getBody().get("job_id");
// Poll
for (int i = 0; i < 60; i++) {
Thread.sleep(3000);
ResponseEntity<Map> status = rest.exchange(
API + "/jobs/" + jobId, HttpMethod.GET,
new HttpEntity<>(headers), Map.class);
if ("done".equals(status.getBody().get("status"))) {
String url = (String) status.getBody().get("download_url");
byte[] epub = rest.getForObject(url, byte[].class);
Path out = Files.createTempFile("converted", ".epub");
Files.write(out, epub);
return out;
}
}
throw new RuntimeException("Conversion timed out");
}
}
Add the API key to application.properties: toolkit.api.key=tk_YOUR_KEY_HERE.
FAQ
What Java version is required?
The java.net.http.HttpClient example requires Java 11 or later. The OkHttp example works on Java 8+. Spring Boot 3.x requires Java 17+.
How do I handle large PDFs?
Use streaming upload with BodyPublishers.ofFile(path) instead of reading the whole file into memory. The API accepts files up to 50 MB on the free tier.
Is there a Java SDK?
Not yet — the REST API is straightforward enough that a thin wrapper is not necessary. The examples above are production-ready with minimal modification.
How long does conversion take?
Most PDFs complete in 10–30 seconds. Scanned PDFs (OCR processing) can take up to 2 minutes. The polling loop above handles both cases.
Sign up at toolkit.bot/api — includes a free tier for testing and low-volume use.