API Overview

Use this page as your checklist before calling any endpoint: authenticate requests, respect rate limits, understand credit usage, and set up callbacks/idempotency headers for reliability.

Authentication

  • Generate tokens from Dashboard → Keys.
  • Send them as bearer tokens: Authorization: Bearer pl_xxx.
  • Tokens inherit the permissions of the account that created them.

Example request

curl -X GET https://api.pdfloom.com/v1/convert/url \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Rate Limits

Authenticated capture requests (those with an auth block) are throttled by default at 30 requests/minute over 60 seconds. Regular requests are not globally throttled unless configured by your deployment.

  • Use backoff/retry when you receive HTTP 429.
  • Long-running conversions count toward the limit as soon as the request starts.

Rate Limit Headers

All API responses include rate limit information in headers, allowing you to monitor your usage proactively:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1738483200
  • X-RateLimit-Limit: Maximum requests allowed in the current window
  • X-RateLimit-Remaining: Number of requests remaining in the current window
  • X-RateLimit-Reset: Unix timestamp when the rate limit resets

When rate limited (HTTP 429), you'll also receive a Retry-After header indicating how many seconds to wait:

Retry-After: 30

Response format

Successful responses follow this schema:

{
  "success": true,
  "response": "https://pdfloom-processed.s3.amazonaws.com/generated/pdf/<uuid>.pdf?...",
  "fileSize": 6139
}
  • response is a signed S3 URL that expires in 30 minutes. Download or proxy it immediately.
  • fileSize helps you predict credit consumption (~1 credit per 5 MB).

Errors return HTTP 4xx/5xx with success: false and a descriptive message:

{
  "success": false,
  "message": "Insufficient credits.",
  "status": 402
}

See Errors for common codes (402, 409, 422).

Credits

  • Each request deducts ceil(fileSize / (5 * 1024 * 1024)) credits (~1 credit per 5 MB).
  • Credit use is logged per request in the dashboard.
  • Generator failures do not charge credits; you'll receive success: false.

You can check your current credit balance at any time using the GET /v1/account/credits endpoint without consuming credits.


Service Resilience

Circuit Breaker

PDF-Loom implements a circuit breaker pattern to protect against cascading failures when the generator service is degraded or experiencing issues.

How it works:

  • If 10 generator failures occur within 60 seconds, the circuit "opens"
  • While open (30 seconds), all conversion requests immediately return 503 Service Unavailable without attempting the conversion
  • After 30 seconds, the circuit enters a "half-open" state where one test request is allowed
  • If the test succeeds, the circuit closes and normal operation resumes
  • If the test fails, the circuit remains open for another 30 seconds

503 Response:

{
  "success": false,
  "error_code": "SERVICE_UNAVAILABLE",
  "message": "Generator service is temporarily unavailable. Please try again later.",
  "retry_after": 30
}

The circuit breaker prevents overwhelming a degraded service and ensures faster failure responses during outages. When you receive a 503 with SERVICE_UNAVAILABLE, wait for the duration specified in the retry_after field before retrying.

Optional fields & callbacks

FieldApplies toDescription
callback_urlAll convert/screenshot endpointsHTTPS URL notified when processing finishes (respond with 2xx to acknowledge).
engine_options.timeoutURL & HTML endpointsOverride the default 30s timeout.
engine_options.waitForNetworkToIdleURL & HTML endpointsWait until network is idle before snapshotting.
assets/v1/convert/html, /v1/screenshot/htmlArray of { filename, content } attachments referenced by your HTML.
options.*All endpointsSee the Convert/Screenshot references for per-feature options (format, margins, clip, etc.).
authURL & HTML convert/screenshotUse bearer/header/cookie/basic/form/script auth to capture behind login. HTTPS required; see Authenticated capture. Auth calls are rate-limited (default 30/min).

Idempotency

Provide an Idempotency-Key header for every request (UUID recommended). We store keys for five minutes:

  • Reusing a key while a request is running returns HTTP 409 with message: "This idempotency key is already being processed."
  • Reusing a key after completion returns the cached response and avoids double-charging credits.
-H "Idempotency-Key: 6b2f7c5a-1cb2-42b2-a099-42f1e2f729c7"

Webhooks

  • Paddle webhooks hit /paddle/webhook and are signature-verified.
  • Your own conversion callbacks (callback_url) receive the original payload plus result metadata. If you configure CALLBACK_SIGNING_SECRET, verify the X-PDFLoom-Signature header in your handler.

Need more detail? Jump to Authentication, Errors, or the Convert and Screenshot references.

SDK quickstart

Each SDK example should include:

  • Authorization: Bearer ... header with your API token
  • Content-Type: application/json
  • Idempotency-Key header
  • Optional callback_url where you acknowledge receipt with a 2xx response
await fetch('https://api.pdfloom.com/v1/convert/html', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.PDFLOOM_TOKEN}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({
    content: '<html>...</html>',
    callback_url: 'https://example.com/conversion-webhook',
    options: { format: 'A4' },
  }),
})
import os, uuid, requests

resp = requests.post(
  'https://api.pdfloom.com/v1/convert/url',
  headers={
    'Authorization': f"Bearer {os.environ['PDFLOOM_TOKEN']}",
    'Content-Type': 'application/json',
    'Idempotency-Key': str(uuid.uuid4()),
  },
  json={
    'url': 'https://example.com',
    'callback_url': 'https://example.com/webhook',
  },
)
print(resp.json())
<?php
$client = new GuzzleHttp\Client();
$response = $client->post('https://api.pdfloom.com/v1/convert/url', [
  'headers' => [
    'Authorization' => 'Bearer '.getenv('PDFLOOM_TOKEN'),
    'Content-Type' => 'application/json',
    'Idempotency-Key' => uniqid('req_', true),
  ],
  'json' => [
    'url' => 'https://example.com',
    'callback_url' => 'https://example.com/webhook',
  ],
]);

Was this page helpful?