Data residency
Formfeed renders in the EU only: documents are rendered in Frankfurt and stored in the European
Union. One part is not limited to the EU, the API gateway on Cloudflare's edge; the table says what
it holds. The endpoint to document in your integration is https://api-eu.formfeed.dev/v1.
Components
| Component | Provider and location | Holds |
|---|---|---|
| Database, authentication, font storage | Supabase, Frankfurt (AWS eu-central-1) | accounts, templates, render metadata, fonts, and the requests of renders while the workspace keeps them |
| Rendering and conversion | Fly.io, Frankfurt (fra) | The render service (Chromium), the office converter (LibreOffice) and the service that makes and checks e-invoices and PDF/UA-1 files. Documents are held in memory while they are worked on, nothing else of them persists; fonts and images that templates load from the web are cached on the render servers' disks for up to 7 days. The render service also sends webhook events and copies into your own bucket. |
| Output storage and delivery | Cloudflare R2 (EU jurisdiction) behind cdn.formfeed.dev | rendered files until they expire, batch zips (see below), and the assembled HTML of a failed render for 24 hours |
| Library and template files | Cloudflare R2 (EU jurisdiction) | files uploaded to the file library, brand kit logos, Word and PowerPoint template files |
| API gateway | Cloudflare edge, executed at the location closest to the caller | request handling; forwards payloads to Frankfurt without storing them. Keeps API key metadata, template versions and the brand kit for a minute, font lists for ten minutes and the replies to requests with an idempotency key for 24 hours in Cloudflare's global key-value store, and counts requests per workspace for the rate limit. formfeed listen relays webhook events through an object in Cloudflare's EU jurisdiction that stores nothing |
| Resend (USA, EU standard contractual clauses) | recipient addresses and the text of transactional mails | |
| Billing | Stripe (merchant of record) | billing contact, invoices, payment data |
| Errors and uptime | Sentry (EU data region), Better Stack | error traces without document contents, public endpoint checks |
The full list with change notifications is the sub-processor page.
What leaves the EU
Rendered documents leave the EU only when the workspace configures its own destination
(bring your own storage): then the render service in Frankfurt copies each
document into the bucket the workspace connected, wherever that bucket is. You choose that
destination. Your own bucket is not a Formfeed sub-processor, so the sub-processor list does not
name it. The same goes for your webhook endpoints: an event carries the render with its download
link and your meta, and goes wherever the endpoint's URL points.
These parts are not limited to the EU:
- The gateway on Cloudflare's edge can execute outside the EU when the caller is outside the EU. It forwards the request to Frankfurt without storing the payload, and keeps the short-lived caches named in the table in Cloudflare's global key-value store.
- Account emails go through Resend and payment data through Stripe, under standard contractual clauses.
Hosts
| URL | Behaviour |
|---|---|
https://api-eu.formfeed.dev/v1 | The EU region. Use this one. |
https://api.formfeed.dev/v1 | The same gateway. It does not pick a region from the host: every request renders in the region of its key's workspace, which is the EU |
https://api-us.formfeed.dev/v1 | Reserved for a US region, which is not open. Today it is the same gateway too and handles a request exactly like api-eu, in the EU |
The region of a render is its workspace's. The EU is the only region that renders, so leave the
region field of a request out; the SDKs and the CLI use the EU host by default.
Retention and deletion
- Outputs are kept for the plan's retention (1 day on Free, 30 days on Starter, 365 days on Pro, without a limit on Business), or for the shorter period a workspace sets under Settings → Output retention (days) or a request sets with
expires_in. Outputs of test renders are kept 24 hours at most.DELETE /renders/{id}/outputsremoves them early (formfeed renders delete-outputs <id>from the command line). See Download links, access and retention. - Batch zips (
"zip": true) are deleted when the first file in them expires, so no document is kept in a zip longer than its own retention. Deleting a render's files earlier (DELETE /renders/{id}/outputs) leaves their copy in the zip until then. A zip's download link expires after seven days at most. - The assembled HTML of a failed render, which contains its data, is kept for 24 hours so the render log can show what failed.
- Render log entries keep metadata (status, timings, units, template version,
meta, the reproducibility record), never the document. They are kept for 13 months: once a month, older entries are deleted, with the batch jobs they belonged to. An entry whose file is still stored stays as long as the file does, which on a plan without a retention limit can be for good. Each billing period's totals stay, butGET /usagelists the days and templates of a period only while its entries exist. - Request payloads are kept only when the workspace turns on Keep render requests in its settings: off by default, 24 hours on Starter, up to 7 days on Pro and above. They are what lets a render be replayed from the render log. An async render holds its request only while it waits in the queue; with the setting off it is deleted the moment the render completes. Post-processing passwords are never kept after a render completes. Every read of a kept request (
GET /renders/{id}/input,formfeed renders pull, the app) is written to the audit log; see Reproduce a failed render. - Copies in a bucket the workspace connected (bring your own storage) are outside Formfeed's retention: Formfeed never deletes them, and deleting outputs, a workspace or the organisation leaves them in place. Deleting a workspace or the organisation destroys the stored bucket credentials at once.
- Deleting a workspace revokes its keys at once; its content is removed after 30 days. Deleting an organisation stops it at once and removes its data 30 days later, and backups within a further 30 days.
Contracts
A data processing agreement (Art. 28 GDPR) is part of every paid plan and available on request for Free workspaces: formfeed.dev/legal/dpa. Security measures are described on formfeed.dev/security.