api2convert 10.3.1

Official Rust SDK for the API2Convert file-conversion API — one-call convert with upload, polling, download and webhook verification.
Documentation

API2Convert Rust SDK

CI Crates.io docs.rs Rust License

Official Rust SDK for the API2Convert file-conversion API.

One call uploads (or references a URL), starts the job, polls it to completion and hands you the result. It is one of the official API2Convert SDKs (PHP, Python, Java, Node.js, Go, Ruby, Rust) that implement the same language-agnostic contract (docs/SDK_CONTRACT.md) and version together.

  • Blocking / synchronous API (like the Python, Go, Java, Ruby and PHP SDKs).
  • Lean dependenciesreqwest, serde_json, hmac, sha2.
  • Secure by construction — secret headers never cross a redirect, uploads use the per-job token (never the account key), and no secret ever appears in an error. See SECURITY.md.

Install

[dependencies]
api2convert = "10"

Requires Rust 1.86+ (set by the reqwest dependency tree).

Quickstart

use api2convert::Api2Convert;

fn main() -> Result<(), api2convert::Api2ConvertError> {
    let client = Api2Convert::new("YOUR_API_KEY")?;

    // Convert a local file and save the result into a directory
    // (the API's filename is used, sanitized against path traversal).
    let result = client.convert("photo.heic", "jpg")?;
    let path = result.save("out/", None)?;
    println!("saved {}", path.display());

    Ok(())
}

The API key also comes from the API2CONVERT_API_KEY environment variable:

let client = api2convert::Api2Convert::from_env()?;

Inputs

convert accepts a local path, a remote URL, in-memory bytes, or a streaming reader. A string starting with http:// / https:// is treated as a URL (sent as a remote input); anything else is a local path.

client.convert("https://example.com/in.png", "jpg")?;   // remote URL
client.convert("in.png", "jpg")?;                         // local path
client.convert(std::fs::read("in.png").unwrap(), "jpg")?; // bytes
client.convert(Input::reader(std::fs::File::open("in.png").unwrap()), "jpg")?; // stream

Conversion options

Target-specific options are a separate map from the SDK controls, so an API option key can never collide with an SDK argument:

use api2convert::{Api2Convert, ConvertOptions};

let result = client.convert_with(
    "in.png",
    "jpg",
    ConvertOptions::new()
        .option("quality", 85)
        .option("strip", true)
        .category("image"),
)?;
let bytes = result.contents(None)?;

Discover the valid options for a target:

let options = client.options("jpg", Some("image"))?;

Download password

A password given at conversion time is remembered on the result and applied automatically:

use api2convert::{Api2Convert, ConvertOptions};

let result = client.convert_with(
    "secret.pdf",
    "png",
    ConvertOptions::new().download_password("s3cr3t"),
)?;
result.save("out/", None)?; // password applied automatically

Async (start now, download later / via webhook)

use api2convert::{Api2Convert, AsyncOptions};

let job = client.convert_async_with(
    "in.png",
    "jpg",
    AsyncOptions::new().callback("https://your.app/webhook"),
)?;
println!("started job {}", job.id);

Verify the webhook delivery in your handler (pass the raw request body and the X-Oc-Signature header):

use api2convert::Api2Convert;

let event = Api2Convert::webhooks().construct_event(raw_body, signature, secret)?;
println!("job {} is {}", event.job.id, event.job.status.code);

Cloud storage

Read an input straight from your own cloud storage (S3, Azure, FTP, Google Cloud) and/or deliver the result back into a bucket. Each per-provider input constructor carries that provider's keys verbatim — flat and lowercase, exactly as the API expects.

use api2convert::{Api2Convert, CloudInput};

// Input from S3: import the source from a bucket, convert it, save the result locally.
let client = Api2Convert::new("YOUR_API_KEY")?;
let input = CloudInput::amazon_s3("my-bucket", "in/photo.png", "AKIA…", "…secret…");
let result = client.convert_cloud(input, "jpg")?;
result.save("out/", None)?;

Deliver the output to a bucket instead with a generic OutputTarget on the output_target control. When an output target is set the conversion delivers straight to your storage and produces no local file, so convert returns the completed job without downloading:

use api2convert::{Api2Convert, ConvertOptions, OutputTarget};

let target = OutputTarget::of("amazons3")
    .parameter("bucket", "my-bucket")
    .parameter("file", "out/photo.jpg")
    .credential("accesskeyid", "AKIA…")
    .credential("secretaccesskey", "…secret…");
client.convert_with("in.png", "jpg", ConvertOptions::new().output_target(target))?;

Credentials ride in the plaintext request body but are redacted everywhere the SDK could surface them — Debug output and error text mask the whole credentials object to [REDACTED] — and are never printed.

Errors

Every fallible call returns Result<_, Api2ConvertError>. Match it to react to specific conditions:

use api2convert::{Api2Convert, Api2ConvertError};

match client.convert("in.png", "not-a-format") {
    Ok(result) => { let _ = result; }
    Err(Api2ConvertError::Validation(e)) => eprintln!("bad request: {}", e.message),
    Err(Api2ConvertError::RateLimit { retry_after, .. }) => {
        eprintln!("rate limited; retry after {:?}s", retry_after)
    }
    Err(Api2ConvertError::ConversionFailed { errors, .. }) => {
        eprintln!("job failed: {errors:?}")
    }
    Err(e) => eprintln!("failed: {e}"),
}

HTTP-error variants expose status(), request_id() (the X-Request-Id) and body().

Full lifecycle control

convert is built on the jobs() resource, which you can drive directly:

use api2convert::Api2Convert;
use serde_json::json;

let job = client.jobs().create(json!({
    "conversion": [{ "target": "png" }],
    "process": false
}), None)?;
client.jobs().upload(&job, "in.jpg", None)?;
client.jobs().start(&job.id)?;
let job = client.jobs().wait(&job.id, None, true)?;
let outputs = client.jobs().outputs(&job.id)?;

Other resources: conversions(), presets(), stats(), contracts().

Configuration

use std::time::Duration;
use api2convert::Api2Convert;

let client = Api2Convert::builder()
    .api_key("YOUR_API_KEY")
    .timeout(Duration::from_secs(60))
    .max_retries(3)
    .poll_interval(Duration::from_secs(1))
    .poll_timeout(Duration::from_secs(600))
    .build()?;
Knob Default Notes
base_url https://api.api2convert.com/v2 trailing / trimmed
timeout 30s JSON requests; min 1s
max_retries 2 transient failures
poll_interval 1s floored to 500ms
poll_max_interval 5s backoff ceiling
poll_timeout 300s capped at 14400s (4h)
max_download_bytes 0 (unlimited) cap downloaded size

Examples

One runnable example per documented guide lives in examples/. Each reads the key from API2CONVERT_API_KEY (and honors API2CONVERT_BASE_URL):

API2CONVERT_API_KEY=<key> cargo run --example quickstart
Example Guide
quickstart Convert a remote JPG to PNG, fetch the job, download
convert-files Browse the conversions catalog, then convert
uploading-files Upload a local file and convert it
job-lifecycle Drive create → add input → start → wait → outputs
add-watermark Stamp a PNG watermark onto a PDF
create-thumbnails Render a PDF page as a PNG thumbnail
compress-files Compress a JPG
create-archives Pack two files into a ZIP
create-hashes Compute the SHA-256 of a ZIP
extract-assets Extract embedded assets from a DOCX
file-analysis Extract a JPG's metadata as JSON
compare-files SSIM-diff two images
capture-website Screenshot a web page to PNG
audio-operations Transcode WAV to AAC
image-operations Resize a JPG
webhooks Start an async conversion with a callback
presets List saved conversion presets
statistics Fetch monthly usage statistics
rate-limits Inspect the account contract / limits
authentication Verify the key by listing jobs

Testing

cargo test                              # unit + offline + security
cargo test --test security              # redirect/leak guarantees only
API2CONVERT_API_KEY=<key> cargo test --test live -- --ignored   # live conformance

The live conformance suite is the executable twin of the examples above: one live test per guide runs the same operation against the real API and asserts success, plus two negative tests (an unknown target is a typed validation error; a bad key is typed and never leaked).

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.

License

MIT © Qaamgo Media GmbH.