API Keys & Security
Two keys, how to rotate them without downtime, and what to do when one leaks.
The two keys
| Client key | Secret key | |
|---|---|---|
| Returns | Published content only | Published and draft content |
| Can write | No | Yes |
| Where it belongs | Browser, mobile app, static site build | Server-side only |
Neither key is a secret you can be careless with.
The Client key is designed to survive being seen (it reads published content and nothing else), so shipping it in a JavaScript bundle is expected and safe. That is not the same as publishing it deliberately. Anyone holding it can read your published content and spend your rate limit, so keep it out of public repositories and rotate it if it escapes. The Secret key must never reach a browser under any circumstances.
Rotating a key without downtime
Rotation runs in two steps so there is never a moment when no valid key exists. Both keys work during the overlap, for as long as you need.
- 1
Generate a secondary key
Nothing changes for your site. The existing key keeps working exactly as before.
- 2
Deploy the secondary key
Update your site and ship it. Take as long as you like. Both keys are accepted while the secondary exists, so a slow rollout costs nothing.
- 3
Promote
The secondary becomes the only key and the old one stops working immediately. Promote once you have confirmed nothing is still calling with the old key.
What a straggler sees after you promote
Anything still sending the old key gets 401 on the next request, not stale content and not a slow failure. If that is a live site, it stops rendering CMS content until it is redeployed with the new key. This is the one step of rotation you cannot undo by clicking again, so confirm before you promote.
Changed your mind mid-rotation? Revoke the secondary instead of promoting it. The original key stays primary and nothing is disrupted.
Allowed Origins
Restricts which websites may call the API with your Client key. Leave it empty and any origin is accepted; add entries and everything else is refused. Your project's website URL is offered as a starting point when you first set it.
This is a browser control, not a security boundary.
Origin headers are set by browsers and can be forged by anything that is not one. Allowed Origins stops your key being used from another website; it does not stop someone calling the API directly with curl. Treat it as protection against casual reuse, and rely on the Client key's read-only, published-only scope for everything else.
The kill switch
Deactivating a project stops it serving content immediately. Reach for it when a key has leaked and you need the bleeding to stop before you have time to rotate properly.
What stops
- Every public API call, Client and Secret alike
- Your live site's CMS content, wherever it renders
- Live Preview, including any preview link already shared
What keeps working
- The dashboard. Editing, saving and publishing are unaffected
- Your content, untouched and intact
- Reactivating, which restores service at once
Nothing is deleted and nothing expires while a project is deactivated. It is a switch, not a demolition. The usual sequence is deactivate, rotate, redeploy, reactivate.
Image URLs and drafts
Images are served straight from a CDN, which is what makes delivery fast and egress free. It also means an uploaded file is reachable by anyone holding its URL, and it becomes reachable the moment you upload it. Publishing does not move the file, it starts returning the URL.
Draft images are unlisted, not access-controlled.
The content API never hands out a draft URL without a Secret key or a preview token, so drafts do not leak through the API. But the file itself sits behind an unguessable URL rather than a permission check. Anyone who obtains that URL, from a shared preview session or a screenshot, can fetch the image whether or not it is published.
Each version gets its own random path. Knowing one image's URL tells you nothing about any other version of it, published or not. Previous versions stay reachable. Rollback needs them, so their files are kept. Rolling back does not make the newer image unreachable to someone who already has its URL. Deleting an asset deletes its files. Edge caches can serve a deleted image for a while afterwards, until the cached copy expires.
For the content this is built for (site copy, product photos, banners), none of this matters. If you are staging imagery whose existence is confidential before launch, treat an uploaded draft as published and keep it out of the CMS until you are ready.
Preview tokens
A preview token grants draft access for a short window, so a client can see unpublished changes on the real site. Send it as a header:
x-duggie-preview-token: TOKEN A custom header makes this a cross-origin preflighted request. The public API accepts it from any origin, so the preflight succeeds even with Allowed Origins configured. The origin check runs in the API rather than in CORS, which means a refused origin returns a normal error response you can read, not an opaque browser failure.