1. Principles
Security work on RelayPDF is aimed at a small set of non-negotiables.
No internet service is perfectly secure. You still have to protect dashboard access, API keys, webhook secrets, and any passwords you send to unlock or protect a PDF.
- TLS for every public API and dashboard connection
- API keys hashed at rest; the full secret is shown once at creation
- No logging of HTML, uploaded files, or PDF passwords
- Generated files requested as a download URL exist for 24 hours, then are deleted
- Private-network and metadata URL fetches are rejected (SSRF controls)
- Failed jobs are never billed and must not increment operations
- Card numbers never touch RelayPDF servers — Stripe is the payment processor
- Customer document content is not used to train public models
2. Infrastructure
RelayPDF does not run its own data centers. The product is split across a small set of providers, each doing a specific job.
Those providers publish their own physical-security, SOC, ISO, and PCI materials. If you need a vendor packet for procurement, email support@relaypdf.com.
Public API
The API is a Cloudflare Worker at api.relaypdf.com. Chromium HTML/URL/Markdown → PDF and screenshots run on Cloudflare Browser Rendering. PDF toolbox jobs (merge, extract, protect, unlock, stamp, rotate, delete-pages, compress, info, text layer, AcroForm fill), barcodes, and zip run in the Worker with pdf-lib and related libraries. LibreOffice and wkhtmltopdf run in a Cloudflare Container (not on the Worker). Temporary files live in Cloudflare R2.
Website and dashboard
relaypdf.com is Next.js on Vercel. Sign-in is Clerk. Account, keys, templates, usage, and the millicent wallet ledger live in Supabase Postgres. Outbound mail is Resend from noreply@relaypdf.com. Inbound support@ and security@ are AgentMail.
Where processing happens
Document jobs are processed on Cloudflare’s network. We do not forward your HTML or files to an unrelated “PDF mill” API. Optional AI template generate/edit is the exception: that path uses Vercel AI Gateway and xAI, only when you call POST /v1/templates/generate.
3. Data in transit
api.relaypdf.com and relaypdf.com require HTTPS. Uploads, JSON bodies, and file downloads use TLS. We do not offer a plaintext API.
- Authorization is an HTTP Bearer API key (`Authorization: Bearer pdf_live_…`). Keys in query strings are rejected.
- Dashboard sessions use Clerk cookies over HTTPS.
- Webhook deliveries to your HTTPS endpoint include `RelayPDF-Signature` (`t=<unix>,v1=<hmac>`). Verify HMAC-SHA256 of `{t}.{raw_body}` with the endpoint secret. Node `verifyWebhook` and Python `verify_webhook` implement that check.
- Per-job `callbackUrl` is HTTPS only and is unsigned. Use dashboard webhooks when you need signatures.
4. Data at rest
What we store, and for how long, depends on the object.
R2 and Postgres use provider-managed encryption at rest. Download URLs are unguessable object ids (`/v1/files/:id`), not sequential integers. GET /v1/files/:id does not require an API key because the id is the capability; treat the URL as a secret for 24 hours.
| Data | Where | Retention |
|---|---|---|
| Generated files (`response: "url"` or async job) | Cloudflare R2, object-specific download URL | 24 hours, then deleted by lifecycle |
| Binary API responses (`response: "binary"`) | Returned on the HTTP response | Not kept as a durable file after the response is sent |
| Saved Handlebars templates and sample data | Supabase Postgres | Until you delete the template or close the account |
| Hashed API keys, names, prefixes, last-used | Supabase Postgres | Until you revoke the key or close the account |
| Request metadata (endpoint, source, status, latency, size, error code) | Supabase Postgres (dashboard Logs) | Typically up to 24 months for billing, abuse, and reliability |
| Wallet ledger and Stripe references | Supabase Postgres; card data at Stripe | Tax and accounting (often seven years in the United States) |
5. How a job is processed
Example: POST /v1/pdf with HTML and `response: "url"`.
Convert jobs follow the same billing and logging rules, but the bytes go to the document container (LibreOffice or wkhtmltopdf) instead of Chromium. Raster uses pdftoppm in that container. If the container is unreachable, you get `503 convert_unavailable` and are not billed.
- The Worker authenticates the hashed API key, applies rate limits, and validates the JSON schema. Invalid bodies never reach Chromium and are not billed.
- Private, loopback, link-local, and cloud-metadata URLs are rejected (`url_not_allowed`) if the job would fetch a URL.
- HTML is sent to Cloudflare Browser Rendering. We do not write that HTML into application logs.
- On success the PDF is stored in R2 with a 24-hour TTL. The JSON response contains `id`, `url`, `filename`, `sizeBytes`, and `expiresAt`.
- A generation_logs row records source (`html`), status, latency, and size — not the document.
- The wallet is debited only after a successful result. A 4xx/5xx leaves the balance unchanged.
- If you registered a dashboard webhook, we POST a signed `job.completed` (or `job.failed`) event. We do not put file bytes in that event.
6. API keys and dashboard access
Write endpoints require a live key. Keys are secrets.
- Created in /dashboard/keys or via `relaypdf login` / `relaypdf setup` (browser Approve). Coding agents must not ask you to paste a key.
- The full `pdf_live_…` value is shown once. After that the UI shows a prefix only.
- The database stores a hash, not the secret. A leaked hash is not enough to call the API.
- Revoke from the dashboard (or admin, for operators). The old secret returns `401 unauthorized`.
- Local `pdf_dev_` keys do not work on production.
- GET /v1/account returns plan, rate tier, and wallet millicents. It does not return email, Stripe ids, or keys, and it is not billed.
7. Logging and support access
Dashboard → Logs shows the last generations: id, source, status, latency. That is metadata, not a document archive.
- We do not log HTML, Markdown, template HTML, uploaded file bytes, or PDF passwords.
- Error JSON uses `error.code` and a short `error.message`. It must not echo your payload.
- Wallet ledger rows show reason, signed amount, running balance, and source on usage — not card numbers or files.
- Operator admin (`/admin`, allowlisted) can see prefixes, wallet, and the same metadata logs — not document bodies.
- There is no “strict logging” add-on because bodies are not stored in logs in the default mode.
8. Files, passwords, and URL fetches
Controls that apply to the bytes you send and receive.
Output files
`response: "url"` and completed async jobs produce a 24-hour R2 object. There is no permanent customer file store and no file-delete API beyond waiting for TTL (or simply not asking for URL mode). Binary mode never creates that object.
Password-protected PDFs
POST /v1/pdf/protect adds a user password (AES-256 via pdf-lib) and optional owner password. POST /v1/pdf/unlock removes protection when you supply the current user password. Extract, bookmarks, stamp, rotate, delete-pages, compress, info, text, and form endpoints accept `password` when the input is encrypted. Compress with a password unlocks first, so the output is unencrypted. We do not persist the password after the request.
Authenticated page fetches
For Chromium URL jobs you can send `options.extraHTTPHeaders` and `options.cookies`. That is how you reach an origin that needs a header or session cookie. Those values are request-scoped; they are not written to logs.
What we will not fetch
http(s) URLs that resolve to loopback, private RFC1918, link-local, or cloud metadata addresses are rejected. `file://` is rejected. Redirects to those targets must not succeed. That applies to PDF, images, convert, merge, zip, stamp, and from-images URL inputs.
{
"url": "https://api.relaypdf.com/v1/files/pdf_...",
"userPassword": "secret",
"filename": "locked.pdf"
}9. Application controls
The Worker validates every write with shared Zod schemas before work starts.
- JSON-only write bodies. Oversized uploads return `413 payload_too_large` (15 MB per file).
- Rate limits: 5 writes / 10 seconds burst per key; 20/min on trial; 60/min after a Stripe top-up or when auto-reload is enabled; 60 file downloads / min / IP. GET /health is not rate limited.
- Account suspend (`403 account_suspended`) is operator-driven.
- CORS allows Authorization and Content-Type so the playground and first-party dashboard can call the API; your key still has to be valid.
10. Payments
RelayPDF uses a prepaid wallet. Stripe Checkout and the billing portal handle cards. We store Stripe customer references and millicent ledger rows, not PAN/CVC.
Stripe is a PCI DSS Level 1 service. Auto-reload charges the saved method when balance drops below your threshold; a failed reload does not invent a document charge.
11. Subprocessors and international transfers
Strategic Products LLC (Florida, USA) operates RelayPDF. Processing is in the United States and on Cloudflare’s global network. EEA/UK/Swiss personal data in your payloads is a transfer you initiate; we rely on Standard Contractual Clauses with subprocessors, as described in the DPA.
The live subprocessor table for customer content is in the DPA. Email support@relaypdf.com if you need a signed copy.
| Provider | Role |
|---|---|
| Cloudflare | API, Browser Rendering, document container, R2 |
| Vercel | Website and dashboard; AI Gateway when you use AI templates |
| Supabase | Postgres (accounts, templates, usage, hashed keys) |
| Clerk | Authentication |
| Stripe | Wallet payments (not document content) |
| Resend / AgentMail | Outbound transactional mail / inbound support and security mail |
| xAI via Vercel AI Gateway | Optional AI template generate/edit only |
| Google Analytics | Marketing-site and dashboard page metrics — not document bodies |
| Google Ads / X Ads | Ad conversion measurement on the website — not document bodies |
12. Incidents, deletion, and contact
Report suspected vulnerabilities or a personal-data incident to security@relaypdf.com. Do not attach live API keys, webhook secrets, or large files to the ticket.
- We will acknowledge security reports and tell you what we know that you need in order to protect your users, within the limits of an ongoing investigation.
- Close the account from the dashboard or by emailing support@relaypdf.com. Keys are revoked. Customer content is deleted or anonymized as described in the Privacy Policy, except records we must keep for billing, tax, or law.
- Legal: /privacy, /terms, /dpa. Entity: Strategic Products LLC, d/b/a RelayPDF, 1583 Hansen Street, Sarasota, FL 34231.