Official SDKs
12 client libraries for the Airpdf Render API. All share the same surface (render, renderAsync, getRender, waitForRender, verifyWebhook) and uniform error model.
Tier 1 — Officially maintained
Hand-crafted, registry-published, full webhook helper, MIT-licensed. Production-ready.
| Language | Package | Min runtime | Install |
|---|---|---|---|
| Node.js / TypeScript | @airpdf/sdk |
Node 18+ | npm install @airpdf/sdk |
| Python | airpdf-sdk |
Python 3.9+ | pip install airpdf-sdk |
| Go | module path announced at release | Go 1.22+ | — |
| Ruby | airpdf-sdk |
Ruby 3.0+ | gem install airpdf-sdk |
Tier 2 — Community / preview
Generated from the OpenAPI spec with hand-written webhook helpers. Breaking changes possible across 0.x. Community PRs welcome.
| Language | Package | Min runtime |
|---|---|---|
| PHP | airpdf/sdk (Composer) |
PHP 8.1+ |
| .NET / C# | Airpdf.Sdk (NuGet) |
.NET 8 / .NET Standard 2.1 |
| Java | it.airpdf:airpdf-sdk (Maven Central) |
Java 17+ |
| Elixir | airpdf_sdk (Hex) |
Elixir 1.15+ |
Tier 3 — Experimental
Reference implementation in the monorepo; not yet published to package registries. Use cURL or another tier directly until promoted.
| Language | Repo |
|---|---|
| Rust | repo announced at release |
| Kotlin | repo announced at release |
| Swift | repo announced at release |
| Dart / Flutter | repo announced at release |
Common surface
Every SDK exposes (names slightly adjusted per language idiom):
| Method | What it does |
|---|---|
render(request) |
Synchronous render. Returns binary PDF bytes or a presigned URL. |
renderAsync(request) |
Enqueues an async render. Returns {id, poll_url} (HTTP 202). |
getRender(id) |
Polls the status of an async render. |
waitForRender(id, options) |
Helper that polls getRender until terminal state. |
verifyWebhook({body, signature, timestamp, secret}) |
HMAC-SHA256 webhook signature check + replay window. |
Error classes
Uniform across all SDKs:
| Class | When | Retry? |
|---|---|---|
AuthError |
401/403 — invalid or revoked API key | No |
QuotaError |
429 — rate limit or monthly quota; carries retryAfter |
After delay |
ClientError |
4xx other — bad request, missing template, schema validation | No (fix payload) |
ServerError |
5xx + network — retryable | Yes (backoff) |
WebhookVerificationError |
Signature/timestamp mismatch | No |
Examples
Node.js / TypeScript
import Airpdf from '@airpdf/sdk';
import { writeFile } from 'node:fs/promises';
const client = new Airpdf({ apiKey: process.env.AIRPDF_API_KEY! });
const result = await client.render({
template: 'invoice',
data: { customer: { name: 'Acme Inc.' } },
});
if (result.kind === 'binary') {
await writeFile('invoice.pdf', result.pdf);
}
Python
import os
from airpdf import Airpdf
client = Airpdf(api_key=os.environ["AIRPDF_API_KEY"])
result = client.render(
template="invoice",
data={"customer": {"name": "Acme Inc."}},
)
with open("invoice.pdf", "wb") as f:
f.write(result.pdf)
Ruby
require "airpdf"
client = Airpdf::Client.new(api_key: ENV.fetch("AIRPDF_API_KEY"))
result = client.render(
template: "invoice",
data: { customer: { name: "Acme Inc." } }
)
File.binwrite("invoice.pdf", result[:pdf]) if result[:kind] == :binary
Go
import (
"context"
"os"
airpdf "<Go module path, announced at release>"
)
client, _ := airpdf.New(os.Getenv("AIRPDF_API_KEY"))
res, _ := client.Render(context.Background(), airpdf.RenderRequest{
Template: "invoice",
Data: map[string]any{"customer": map[string]any{"name": "Acme Inc."}},
})
os.WriteFile("invoice.pdf", res.PDF, 0o644)
Elixir
client = Airpdf.new(api_key: System.fetch_env!("AIRPDF_API_KEY"))
{:ok, %{kind: :binary, pdf: pdf}} =
Airpdf.render(client, template: "invoice", data: %{customer: %{name: "Acme"}})
File.write!("invoice.pdf", pdf)
Async + polling (Node)
const ack = await client.renderAsync({ template: 'report', data: {} });
const final = await client.waitForRender(ack.id, { intervalMs: 1000, timeoutMs: 60_000 });
console.log(final.url);
Versioning
All SDKs are released independently. Each starts at 0.1.0. The HTTP API is versioned separately at /api/v1/...; SDK majors track API majors only when breaking changes happen on the wire.
Contributing
Each SDK lives in its own subdirectory of the monorepo with language-native tooling. PRs welcome — see each SDK’s README.md for build + test instructions.
License
MIT for every SDK.