Skip to content

Latest commit

 

History

History
334 lines (252 loc) · 13.3 KB

File metadata and controls

334 lines (252 loc) · 13.3 KB

API2Convert Java SDK

CI Maven Central Java License

The official Java client for the API2Convert file-conversion API. Convert, compress and transform images, documents, audio, video, ebooks, archives and CAD — and run operations like OCR, merge, thumbnail and website capture — in one line of code.

Api2Convert client = new Api2Convert("YOUR_API_KEY");

client.convert("invoice.docx", "pdf").save("invoice.pdf");

That single call creates a job, uploads your file, starts it, waits for it to finish and gives you back a result you can save. No polling loops, no manual upload handling.

Requirements

  • Java 17+
  • One runtime dependency: Jackson (jackson-databind). The HTTP layer uses the JDK's built-in java.net.http.HttpClient — no extra HTTP dependency.

Install

Maven:

<dependency>
  <groupId>com.api2convert</groupId>
  <artifactId>api2convert-java</artifactId>
  <version>10.3.3</version>
</dependency>

Gradle:

implementation("com.api2convert:api2convert-java:10.3.3")

Get an API key from the API2Convert dashboard / documentation.

Quick start

import com.api2convert.Api2Convert;
import java.util.Map;

// Reads the API2CONVERT_API_KEY environment variable when no key is passed.
Api2Convert client = new Api2Convert("YOUR_API_KEY");

// 1) From a local file
client.convert("photo.png", "jpg").save("photo.jpg");

// 2) From a URL
client.convert("https://example.com/photo.png", "jpg").save("photo.jpg");

// 3) With conversion options (discover them via client.options("jpg"))
client.convert("photo.png", "jpg", Map.of("quality", 85, "width", 1280, "height", 720))
      .save("out/");   // the processed-file directory

convert(input, to, options) — input is a local path String, a public URL, a Path, a byte[] or an InputStream; to is the target format; options are the conversion options for that target. Less-common controls live on ConvertOptions (so they can never collide with an open-ended API option): category, timeout, outputIndex, filename, downloadPassword. The returned ConversionResult lets you:

ConversionResult result = client.convert("report.docx", "pdf");

result.save("report.pdf");       // stream to a file
result.save("downloads/");       // ...or a directory (keeps the server filename)
byte[] content = result.contents();  // ...or get the raw bytes
String url = result.url();       // ...or just the download URL

Password-protect the result

Pass a downloadPassword and the output is locked behind it. The SDK remembers the password and sends it automatically when you download — you don't pass it again:

import com.api2convert.ConvertOptions;

ConversionResult result = client.convert("statement.docx", "pdf", null,
        new ConvertOptions().downloadPassword("hunter2"));

result.save("statement.pdf");    // the password is applied for you

The download URL still needs the password from anywhere else (a browser, cURL, another process), via the X-Api2convert-Download-Password header. When you already hold an OutputFile — e.g. from the Jobs API — hand the password to download():

client.download(output, "hunter2").save("out/");

Asynchronous conversions & webhooks

For long-running jobs, start the conversion and get notified via a webhook instead of waiting:

import com.api2convert.AsyncOptions;

Job job = client.convertAsync("movie.mov", "mp4", null,
        new AsyncOptions().callback("https://your-app.example.com/webhooks/api2convert"));

In your webhook handler, verify and parse the callback:

import com.api2convert.Api2Convert;
import com.api2convert.exception.SignatureVerificationException;
import com.api2convert.webhook.WebhookEvent;

byte[] payload = request.rawBody();                 // the RAW body
String signature = request.header("X-Oc-Signature");

try {
    WebhookEvent event = Api2Convert.webhooks().constructEvent(payload, signature, "YOUR_WEBHOOK_SECRET");
    Job job = event.job();
    // ... react to job.status().code() ...
} catch (SignatureVerificationException e) {
    // respond 400
}

Signed webhooks are being rolled out. Until they are enabled for your account no signature is sent — call Api2Convert.webhooks().parse(payload) (or pass an empty secret) to deserialize the callback without verifying.

Cloud storage

Read an input straight from your own S3, Azure Blob or Google Cloud Storage, and/or deliver the converted output back into a bucket. Use the per-provider CloudInput factory for inputs (its arguments are the provider's flat/lowercase keys, exactly as the API expects), and the generic OutputTarget for outputs:

import com.api2convert.ConvertOptions;
import com.api2convert.enums.CloudProvider;
import com.api2convert.model.CloudInput;
import com.api2convert.model.OutputTarget;
import java.util.Map;

// Input from S3: fetch the file from your bucket and save the result locally.
CloudInput input = CloudInput.amazonS3("my-bucket", "invoices/invoice.docx",
        "AKIA...", "s3-secret-access-key");

client.convert(input, "pdf").save("invoice.pdf");

// Output to S3: convert a local/URL input and deliver the result into a bucket.
OutputTarget target = OutputTarget.of(CloudProvider.AMAZON_S3,
        Map.of("bucket", "my-bucket", "file", "results/invoice.pdf"),
        Map.of("accesskeyid", "AKIA...", "secretaccesskey", "s3-secret-access-key"));

client.convert("invoice.docx", "pdf", null, new ConvertOptions().outputTargets(target));

azure(...) and googleCloud(...) inputs work the same way. When an output target is set the conversion has no downloadable output — convert() returns the completed job (via result.job()) without downloading. Cloud credentials are redacted ([REDACTED]) in exceptions and object inspection, and the SDK never logs them.

Error handling

Every failure is an unchecked exception extending com.api2convert.exception.Api2ConvertException:

import com.api2convert.exception.*;

try {
    client.convert("photo.png", "jpg").save("photo.jpg");
} catch (ValidationException e) {
    // bad target / option — e.getMessage() explains
} catch (AuthenticationException e) {
    // bad or missing API key
} catch (RateLimitException e) {
    // too many requests — retry after e.getRetryAfter() seconds
} catch (ConversionFailedException e) {
    // the job failed — inspect e.errors()
}
Exception When
AuthenticationException 401 / 403 — bad or missing key
PaymentRequiredException 402 — no remaining quota
ValidationException 400 / 422 — invalid request (e.g. unknown target)
NotFoundException 404 — resource doesn't exist
RateLimitException 429 — exposes getRetryAfter()
ServerException 5xx
ConversionFailedException the job reached failed; exposes getJob() and errors()
TimeoutException the job didn't finish within the poll timeout
SignatureVerificationException a webhook payload failed verification

Transient failures (429, 5xx, network errors) are retried automatically with jittered exponential backoff. A non-idempotent POST (e.g. creating a job) is never blindly retried, so a transient error can't create a duplicate job — pass an idempotency key to make it retry-safe: client.jobs().create(payload, "my-idempotency-key").

Power user: the full job API

convert() is sugar over the Jobs API. Drop down to it for compound jobs, merges, presets, custom polling or job chaining:

Job job = client.jobs().create(Map.of(
        "process", false,
        "conversion", List.of(Map.of("target", "pdf", "options", Map.of("pdf_a", true)))));

client.jobs().upload(job, "contract.docx");                 // local file
client.jobs().addInput(job.id(), Map.of(                    // ...or a URL
        "type", "remote", "source", "https://example.com/appendix.docx"));

client.jobs().start(job.id());
Job done = client.jobs().await(job.id(), 120);              // poll to completion (120s timeout)

for (OutputFile output : done.output()) {
    client.download(output).save("out/");
}

Available resources: jobs(), conversions() (the catalog + option discovery), presets(), stats(), contracts().

Discover the valid options for any target:

Map<String, Object> options = client.options("jpg");   // -> { quality: {...}, width: {...}, ... }

Note: the poll-to-completion method is jobs().await(...) (not wait, which is reserved by java.lang.Object). This is the only public name adapted to Java idiom.

Configuration

import com.api2convert.http.Config;

Api2Convert client = new Api2Convert("YOUR_API_KEY", Config.builder()
        .timeout(30)          // per-request network timeout (seconds)
        .maxRetries(2)        // automatic retries for transient failures
        .pollInterval(1.0)    // first poll interval when waiting (seconds)
        .pollMaxInterval(5.0) // backoff cap (seconds)
        .pollTimeout(300)     // give up waiting after this many seconds
        .build());

Bring your own HTTP transport by implementing com.api2convert.http.HttpSender and passing it as the third constructor argument.

Security — never publish your API key

  • Never hard-code or commit your API key. Load it from the environment (API2CONVERT_API_KEY) or a secrets manager.
  • In CI, store it as a masked & protected variable and never print it to logs.
  • Treat the per-job upload token and your webhook signing secret with the same care.
  • The SDK never logs your key/token and never puts them in exception messages. Authenticated requests never follow a redirect (a redirect could otherwise forward the key to another host); only the self-contained, no-auth download path follows redirects.
  • If a key is ever exposed, revoke and rotate it in the API2Convert dashboard immediately.

See SECURITY.md.

Development

mvn verify        # compile + run the offline unit tests

Live conformance tests run against the real API when API2CONVERT_API_KEY is set (they auto-skip otherwise):

API2CONVERT_API_KEY=... mvn verify -DexcludedGroups=

The live conformance suite doubles as an executable, end-to-end tour of the SDK: it runs the same 20 documented examples end to end (plus two negative scenarios — an invalid target is a typed validation error, and a bad key is a typed auth error that never leaks the credential). Each test mirrors one runnable file in examples/ and one guide on api2convert.com.

It runs automatically against the real API on every release tag (see .github/workflows/live-conformance.yml), so a published version is always verified end to end.

Runnable examples

Each file in examples/ is a self-contained program that reads the key from API2CONVERT_API_KEY (and honors API2CONVERT_BASE_URL). Build the jar (mvn -B package), then run one with the SDK + Jackson on the classpath, e.g.:

API2CONVERT_API_KEY=your-key java -cp "target/classes:libs/*" Quickstart
Guide Example
Quick start Quickstart.java
Convert files ConvertFiles.java
Uploading files UploadingFiles.java
The job lifecycle JobLifecycle.java
Add a watermark AddWatermark.java
Create thumbnails CreateThumbnails.java
Compress files CompressFiles.java
Create archives CreateArchives.java
Create hashes CreateHashes.java
Extract assets ExtractAssets.java
File analysis FileAnalysis.java
Compare files CompareFiles.java
Capture a website CaptureWebsite.java
Audio operations AudioOperations.java
Image operations ImageOperations.java
Webhooks Webhooks.java
Presets Presets.java
Statistics Statistics.java
Rate limits & contracts RateLimits.java
Authentication Authentication.java

This SDK is hand-written and kept in sync with the API by an AI agent — see AGENTS.md and docs/SDK_CONTRACT.md. Notable changes are recorded in docs/CHANGELOG.md.

License

MIT — see LICENSE.