Privacy Policy

Last updated: 14 May 2026

1. Data controller

PaperJet is operated from France. Use [email protected] for privacy questions and data subject requests. PaperJet is currently operated and maintained by a single maintainer. We do not currently appoint a Data Protection Officer; requests are handled within the time required by applicable law.

2. What we collect

When you create an account:

  • Email address (the only required field — used for magic-link sign-in + service notifications).
  • Hashed magic-link tokens during the verification window (≤ 10 min).
  • Stripe customer ID only if/when paid billing is enabled and you start a paid plan (Stripe stores the actual payment method).

When you use the API:

  • API key hashes (BLAKE3 digest) — we never store the plaintext key.
  • Render metadata: size, duration, status (ok / failed / timeout), template id, api key id, timestamp. Retained for 30 days on every plan.
  • Templates you upload (the Typst source code, kept until you delete them or your account).
  • Webhook endpoint URLs you register, the encrypted signing secret (needed to derive HMAC on every delivery), the latest delivery status code, bounded response preview, error label, duration, and timestamp.

For every authenticated request:

  • IP address, TRUNCATED before storage (last octet zeroed for IPv4, last 80 bits zeroed for IPv6).
  • User-agent string, sanitized (control chars replaced) and capped at 500 chars.
  • Request id (a UUIDv7 we mint per request, useful for support).

What we do NOT collect or store:

  • Rendered PDF bytes for archival. Ordinary render responses are streamed to your client and not kept as files; if you send an Idempotency-Key, a successful response can be cached for up to 24 h so retries can replay it safely.
  • Full IP addresses (truncated as above).
  • Card numbers or any payment method (Stripe handles this).
  • Tracking cookies, fingerprints, or third-party analytics. The dashboard uses one HttpOnly session cookie (better-auth) and that's it.

3. Why we process

Legal bases under Article 6 GDPR:

  • Contract performance (Art. 6(1)(b)) — providing the API service you signed up for: account, authentication, render execution, and billing if/when paid billing is enabled.
  • Legitimate interest (Art. 6(1)(f)) — securing the platform against abuse: rate-limiting, audit-log of sensitive events, brute-force defence.
  • Legal obligation (Art. 6(1)(c)) — billing records are retained for the duration French commercial law requires (10 years for invoices).

4. Where the data lives

PaperJet is designed to run on Cloudflare with EU/GDPR constraints in mind. Before regulated production use, verify the active Cloudflare account, data-location settings, and sub-processors:

  • D1 (SQLite) — accounts, API keys, render metadata, audit log, idempotency rows, Stripe webhook ledger.
  • R2 — uploaded templates.
  • KV — short-lived auth stamps, session cache, and rate-limit counters.
  • Durable Objects — sliding-window rate limiters.
  • Containers — the rendering compute, ephemeral.

Cloudflare, Stripe, Resend, and other infrastructure providers may process data in multiple countries depending on their services, routing, legal requirements, and customer location. We do not promise EU-only processing unless agreed in a separate written data-processing agreement.

5. Sub-processors

We rely on the following service providers as sub-processors:

Cloudflare, Inc.

Purpose
Compute, storage, CDN, DDoS protection
Region
EU (data) / Global (edge)

Stripe Payments Europe

Purpose
Payment processing, invoicing, tax calculation, customer portal
Region
EU / Global, depending on Stripe processing and customer location

Resend

Purpose
Transactional email (magic link, billing)
Region
US (SCC + Data Privacy Framework)

This list is reviewed before adding any new sub-processor.

6. Retention

  • Account, API keys, templates, webhook endpoints — for the life of your account; deleted when you delete the account.
  • Render metadata — 30 days on every plan.
  • Audit log — 1 year (auth, key, template, subscription, webhook events). On account deletion, the user_id is anonymised (set to NULL) but the row stays — required for incident forensics + abuse-prevention legitimate interest.
  • Billing records — 10 years (French commercial law).
  • Idempotency cache, rate-limit counters — 24 h in D1 for committed idempotency responses / typically 60 s for rate-limit counters.

7. Your rights

Under the GDPR, you can:

  • Access — request a copy of the data we hold about you.
  • Rectify — correct any inaccurate data (your email lives in your account; other fields are derived).
  • Erase — delete your account from Settings → Delete account. Cascades to all your API keys, templates, render metadata, sessions, and webhook endpoints. Audit log entries are anonymised (NULL user_id) but retained per Article 6.
  • Portability — request a JSON export of your account data.
  • Object — to processing based on legitimate interest.
  • Restrict — processing while a request is being handled.
  • Lodge a complaint — with your local supervisory authority (in France: CNIL).

For any of the above, use the contact address listed in the Data controller section. We respond within the time required by applicable law.

8. Security

Technical and organisational measures we apply:

  • HTTPS-only (HSTS preload, no plaintext fallback).
  • API keys hashed at rest (BLAKE3 digest; plaintext keys are not intentionally logged).
  • Magic-link tokens hashed at rest, single-use, 10-min expiry.
  • HttpOnly + SameSite=Lax session cookies on the dashboard.
  • Strict Content Security Policy (nonce-based, no unsafe-inline).
  • Per-thread seccomp + landlock sandbox around the Typst compiler.
  • Audit log of every authentication attempt, key mint/revoke, template / webhook change, subscription event.
  • Encrypted transport with all sub-processors (TLS 1.2+).

Security disclosures use the same contact address, with a [security] subject prefix. We review reports in good faith and may credit reporters who use coordinated disclosure.

9. Children

The service is not directed at children under 16. We do not knowingly collect data from children. If you believe a child has signed up, contact us and we'll delete the account.

10. Changes to this policy

We may update this policy as the service, infrastructure, or legal requirements change. Changes take effect when posted unless a later date is stated. For material changes, we will make reasonable efforts to notify affected customers by email or in-product notice. The "last updated" date at the top of this page reflects the most recent revision.