Authentication and test mode
Authenticate with API keys, choose scopes, use test mode, roll and revoke keys, and find the API host for your data.
Every API request is authenticated with an API key that belongs to one workspace. Keys have a mode (test or live), a set of scopes and optional restrictions. Create and manage them under API keys in the dashboard at https://app.dynamicdocumentapi.com.
Send your API key
Pass the key as a bearer token in the Authorization header:
curl https://api-eu.dynamicdocumentapi.com/v1/account \
-H "Authorization: Bearer $DYNAMIC_DOCUMENT_API_KEY"Tools that can only set a custom header can send the key in X-API-Key instead:
curl https://api-eu.dynamicdocumentapi.com/v1/account \
-H "X-API-Key: $DYNAMIC_DOCUMENT_API_KEY"A request without credentials fails with 401 authentication_required, and an unknown or malformed key fails with 401 invalid_api_key. OAuth 2.0 access tokens for marketplace apps and integrations are planned.
Key format
Keys have this structure:
dda_live_<24-character key ID>_<40-character secret>
dda_test_<24-character key ID>_<40-character secret>The mode is part of the key, so you can tell test and live keys apart at a glance.
Only a hash of the secret is stored. The full key is displayed once, when you create it; afterwards the dashboard shows only the prefix and the last four characters. If you lose a key, roll it or create a new one. Creating a key requires you to confirm your identity again.
Keys, scopes and restrictions
A workspace can have any number of keys, for example one per service or environment. Owners and Admins manage all keys in a workspace, and Developers manage their own keys. Each key has:
- a name, so you can tell what it's used for
- a mode:
testorlive - scopes that limit what it can do
- an optional template allowlist
- an optional IP allowlist
- an optional expiry date
Scopes
Give each key only the scopes it needs. A request outside the key's scopes fails with 403 insufficient_scope.
| Scope | Allows |
|---|---|
render:write | Creating renders with POST /v1/renders and the /v1/pdf/… and /v1/images/… convenience endpoints, as well as batches, PDF tools, e-invoice XML and uploads |
renders:read | Listing and retrieving renders, batches and email sends, with their files and logs |
renders:delete | Purging render files with DELETE /v1/renders/{id}/files |
templates:read | Listing templates and reading their schemas, versions and sources |
templates:write | Creating templates, replacing drafts, publishing, rolling back and deleting templates through the API |
webhooks:read, webhooks:write | Reading webhook endpoints and deliveries; managing endpoints and replaying deliveries |
storage:read, storage:write | Reading storage destinations; creating, changing, testing and deleting them |
signed_links:read, signed_links:write | Reading signed links; creating, changing, signing and deleting them |
email:read, email:write | Reading the connections and rules of email delivery; creating, changing, testing and deleting them |
account:read | Reading the account, plan, limits and usage (GET /v1/account, GET /v1/usage) |
For webhooks, storage, signed links and email, the write scope includes reading: a key with only storage:write can also list and retrieve storage destinations.
Template allowlist
Restrict a key to specific templates, for example a key used by a no-code tool that should only generate one document type. Rendering any other template fails with 403 template_not_allowed_for_key.
IP allowlist
Restrict a key to one or more IPv4 or IPv6 ranges in CIDR notation, such as 203.0.113.0/24. Requests from other addresses fail with 403 ip_not_allowed. To restrict every key of the workspace, set the API IP allowlist under Settings → Security in the dashboard. It works the same way, and a key with its own allowlist has to pass both.
Expiry
Keys can expire on a date you choose. You receive an email before a key expires, and requests with an expired key fail with 401 api_key_expired. An api_key.expiring webhook event is planned.
Test mode
Test keys let you build and run automated tests against the real API without using any of your renders:
| Test key | Live key | |
|---|---|---|
| Prefix | dda_test_ | dda_live_ |
| Billed renders | Free; not counted in usage | Billed per the render table |
| Output | Watermarked "TEST" (e-invoice XML: a TEST note) | Clean |
| File storage | Deleted after 24 hours | Kept for your workspace's retention period |
| Webhooks | Delivered and signed | Delivered and signed |
| Rate limit | Test renders per minute by plan: 10 (Free), 60 (Starter, Growth), 120 (Pro), 300 (Scale) | Your plan's rate limits |
| Template drafts | "version": "draft" allowed | Only if your workspace settings allow it |
| Email verification | Not required | Required (403 email_not_verified) |
Renders made with a test key are always test renders and have "test": true. Sending "test": true with a live key fails with 403 test_key_required; use a test key instead.
Use test keys in development, CI and staging. Test renders go through the same pipeline as live renders, so layouts, page counts, errors and webhooks match live behaviour apart from the watermark.
Roll and revoke keys
Rotate keys regularly and whenever someone who had access leaves.
- Roll a key to create a new secret with the same name, mode, scopes and restrictions. Choose a grace period of 0, 1, 24 or 72 hours during which the old secret keeps working, deploy the new key, and let the old one lapse.
- Revoke a key to disable it immediately. Requests with a revoked key fail with
401 api_key_revoked.
The dashboard shows when each key was last used, the last IP address and request counts for the past 24 hours and 30 days. Keys that haven't been used for 90 days are flagged so you can remove them.
If a key leaks
Roll it with a grace period of 0 hours, or revoke it, then deploy the replacement. Review recent renders in the dashboard for requests you don't recognise.
Never use secret keys in browsers
CORS is not enabled for secret API keys, so browsers can't call the API directly, and a key embedded in a web page, mobile app or public repository can be copied by anyone who sees it. Call the API from your backend and pass the resulting file or signed URL to the client.
To let a page or an email request an image or PDF without a key, use signed links: URLs signed on your server with a per-link secret. Publishable keys that can only create signed URLs for allowlisted templates and origins are planned.
Data residency
Render payloads and generated files are processed and stored in the EU. The API answers on two hosts:
| Host | Region |
|---|---|
https://api-eu.dynamicdocumentapi.com | EU (default) |
https://api.dynamicdocumentapi.com | EU (alias) |
Append /v1 to the host to get the base URL, for example https://api-eu.dynamicdocumentapi.com/v1.
Request IDs
Every response has an X-Request-Id header, and error responses repeat it in the request_id field. Log it with your own request data, and include it when you contact support at support@dynamicdocumentapi.com. You can also send your own X-Request-Id header to correlate API calls with your logs.