Official .NET / C# SDK for the API2Convert file-conversion API. Convert, compress and transform images, documents, audio, video, ebooks, archives and CAD with one line of code.
- One-call conversions —
ConvertAsync(input, to)hides the create → upload → poll → download lifecycle for local files, URLs and streams. - Async-first — every I/O method returns a
Taskand takes aCancellationToken. - Typed errors —
AuthenticationException,ValidationException,RateLimitException,ConversionFailedException, … all under oneApi2ConvertExceptionbase. - Secure by default — secrets never appear in logs, URLs or exceptions, and a request carrying a secret never follows an HTTP redirect. See SECURITY.md.
- Zero third-party runtime dependencies —
HttpClient,System.Text.JsonandSystem.Security.Cryptographyonly.
Targets .NET 8.
dotnet add package Api2Convertusing Api2Convert;
using var client = new Api2ConvertClient("YOUR_API_KEY"); // or set API2CONVERT_API_KEY
// Convert a local file and save the result.
var result = await client.ConvertAsync("invoice.docx", "pdf");
string path = await result.SaveAsync("invoice.pdf");
// Convert a public URL and read the bytes into memory.
var png = await client.ConvertAsync("https://example.com/photo.jpg", "png");
byte[] bytes = await png.ContentsAsync();The API key is read from the constructor argument, or falls back to the API2CONVERT_API_KEY
environment variable.
Discover the valid options for a target, then pass them to ConvertAsync:
IReadOnlyDictionary<string, object?> schema = await client.OptionsAsync("jpg");
var result = await client.ConvertAsync(
"photo.png",
"jpg",
new Dictionary<string, object?> { ["quality"] = 80, ["strip"] = true });Less-common controls live on ConvertOptions, kept separate from the open-ended options map so they
can never collide with an API option key:
var result = await client.ConvertAsync(
"scan.tiff",
"pdf",
options: null,
opts: new ConvertOptions { Category = "document", DownloadPassword = "hunter2", Timeout = 600 });A download password supplied at conversion time is remembered on the result and sent
automatically (as X-Api2convert-Download-Password) on every download from it.
StartConversionAsync starts a job and returns immediately without polling. Pass a callback URL to be
notified when it finishes (this is the contract's convertAsync, renamed so the Async suffix keeps
its .NET "returns a Task" meaning):
var job = await client.StartConversionAsync(
"https://example.com/big.mov",
"mp4",
opts: new AsyncOptions { Callback = "https://app.example.com/hooks/a2c" });
// later — poll it yourself, or handle the webhook (below)
var done = await client.Jobs.WaitAsync(job.Id);Point a job's callback at your endpoint, then verify the raw request body against your signing secret before trusting it:
using Api2Convert;
using Api2Convert.Exceptions;
// framework-agnostic; wire rawBody / signatureHeader to your web request
try
{
var evt = Api2ConvertClient.Webhooks().ConstructEvent(rawBody, signatureHeader, secret);
if (evt.Job.IsCompleted)
{
foreach (var output in evt.Job.Output)
{
// e.g. enqueue a download of output.Uri
}
}
}
catch (SignatureVerificationException)
{
// respond 400 Bad Request — do not trust the payload
}Verification is HMAC-SHA256 over the raw body with a constant-time comparison. An empty secret
deliberately skips verification (use Webhooks().Parse(rawBody) when signed webhooks are not enabled
on your account yet).
Read an input straight from customer-owned storage (S3, Azure Blob, FTP, Google Cloud), deliver the
converted output into a bucket, or both. Build a cloud input with a per-provider factory whose
arguments carry each provider's required keys verbatim (flat/lowercase, exactly as the API expects) and
hand it to ConvertAsync like any other input:
using Api2Convert.Models;
// Import from S3 — the API fetches the object itself (like a URL: a single started job).
var input = CloudInput.AmazonS3(
bucket: "my-bucket",
file: "invoices/invoice.docx",
accesskeyid: "AKIA...",
secretaccesskey: "...");
var result = await client.ConvertAsync(input, "pdf");
await result.SaveAsync("invoice.pdf"); // a normal, downloadable resultTo deliver the output into a bucket, attach an OutputTarget via the OutputTargets option. Output
uses the generic target (a CloudProvider plus free-form parameters / credentials), not a
per-provider factory:
using Api2Convert.Enums;
using Api2Convert.Models;
var target = OutputTarget.Of(
CloudProvider.AmazonS3,
parameters: new Dictionary<string, object?> { ["bucket"] = "my-bucket", ["file"] = "out/invoice.pdf" },
credentials: new Dictionary<string, object?> { ["accesskeyid"] = "AKIA...", ["secretaccesskey"] = "..." });
// With an output target set, the conversion delivers straight to your storage and produces no local
// output — ConvertAsync returns the completed job (result.Job) and there is nothing to download.
var result = await client.ConvertAsync(
"invoice.docx",
"pdf",
opts: new ConvertOptions { OutputTargets = new[] { target } });Azure, Ftp and GoogleCloud input factories exist too (same shape). Credentials ride in the request
body, so the SDK masks the whole credentials object to [REDACTED] in ToString() / logs and never
prints or echoes it in error text.
ConvertAsync is built on the resource API, which you can use directly for compound jobs, job
chaining, custom polling or presets:
var job = await client.Jobs.CreateAsync(new Dictionary<string, object?>
{
["conversion"] = new[] { new Dictionary<string, object?> { ["target"] = "png" } },
["process"] = false,
});
await client.Jobs.UploadAsync(job, "input.jpg");
await client.Jobs.StartAsync(job.Id);
var done = await client.Jobs.WaitAsync(job.Id);Resources: client.Jobs, client.Conversions, client.Presets, client.Stats, client.Contracts.
using Api2Convert.Exceptions;
try
{
await client.ConvertAsync("photo.jpg", "not-a-format");
}
catch (ValidationException e) { Console.WriteLine($"Invalid request: {e.Message} (HTTP {e.StatusCode})"); }
catch (RateLimitException e) { Console.WriteLine($"Slow down; retry after {e.RetryAfter}s"); }
catch (ConversionFailedException e) { Console.WriteLine($"Job {e.Job.Id} failed: {e.Message}"); }
catch (Api2ConvertException e) { Console.WriteLine($"SDK error: {e.Message}"); } // catch-all baseTransient failures (429 / 5xx / network) are retried automatically with capped, jittered exponential
backoff honoring Retry-After; a non-idempotent POST is never blindly retried, so a transient error
cannot create a duplicate job.
var config = new Config.Builder()
.BaseUrl("https://api.api2convert.com/v2")
.Timeout(30) // per-request seconds
.MaxRetries(2)
.PollInterval(1.0) // seconds; floored so it can never busy-loop
.PollMaxInterval(5.0)
.PollTimeout(300) // seconds; capped so it can never poll unbounded
.Build();
using var client = new Api2ConvertClient("YOUR_API_KEY", config);Plug in your own transport (or a mock) via the IHttpSender seam:
new Api2ConvertClient(apiKey, config, myHttpSender).
make check # build + offline unit suite + independent security suite (no API key)
make test-security # just the security suite (real loopback servers)
# Live conformance against the real API (auto-skips without a key):
API2CONVERT_API_KEY=<your key> make test-live
# Or run everything in a container on a pinned .NET SDK:
make docker-checkThe live conformance suite doubles as an
executable, end-to-end tour of the SDK — there is one test per documented guide (plus two negative
tests), each a self-contained usage example that mirrors the runnable file of the same name in
examples/.
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.
Every documented guide has a runnable, self-contained example in
examples/Examples. They live in one console project; pass the guide slug to run
one (the key is read from API2CONVERT_API_KEY, and API2CONVERT_BASE_URL retargets the host):
API2CONVERT_API_KEY=your-key dotnet run --project examples/Examples -- quickstartRun it with no argument to list every guide.
| Guide | File |
|---|---|
| Quickstart — convert a remote JPG to PNG, then download | Quickstart.cs |
| Convert Files — browse the catalog, then convert | ConvertFiles.cs |
| Uploading Files — one-call upload + convert of a local file | UploadingFiles.cs |
| Job Lifecycle — create → add input → start → wait → outputs | JobLifecycle.cs |
| Add a Watermark — stamp a PNG onto a PDF | AddWatermark.cs |
| Create Thumbnails — first PDF page → PNG thumbnail | CreateThumbnails.cs |
| Compress Files — shrink a JPG | CompressFiles.cs |
| Create Archives — bundle two files into a ZIP | CreateArchives.cs |
| Create Hashes — SHA-256 of a ZIP | CreateHashes.cs |
| Extract Assets — pull assets out of a DOCX | ExtractAssets.cs |
| File Analysis — read a JPG's metadata as JSON | FileAnalysis.cs |
| Compare Files — SSIM diff of two images | CompareFiles.cs |
| Capture a Website — screenshot a URL to PNG | CaptureWebsite.cs |
| Audio Operations — re-encode WAV → AAC | AudioOperations.cs |
| Image Operations — resize a JPG | ImageOperations.cs |
| Webhooks — async convert with a callback, and verify a delivery | Webhooks.cs |
| Presets — list saved presets | Presets.cs |
| Statistics — usage stats for a month | Statistics.cs |
| Rate Limits — read contract information | RateLimits.cs |
| Authentication — list jobs to confirm the key works | Authentication.cs |
MIT © Qaamgo Media GmbH.