Limits

What the API enforces, and what happens when you reach it.

Per plan

FreePro
Projects11 per slot, plus one free-tier project
Assets per project50No published limit
Members per project2No published limit
Storage250 MB2 GB per project slot, pooled
Max file size5 MB25 MB
API requests5,000 / monthUnmetered

“No published limit” means exactly that: there is no cap you will meet in normal use. A high backstop exists to stop runaway automation, and you will never see it unless something is wrong.

How storage is counted

  • Paid storage is pooled across your account. Each project slot grants 2 GB, and every paid project draws from the combined total. Three slots is one 6 GB pool, not three separate 2 GB allowances.
  • A free-tier project keeps its own allowance. The bonus free-tier project that comes with a paid plan has its own 250 MB and is excluded from the account pool entirely — filling it does not touch your paid storage, and vice versa. It follows the free tier's 5 MB file limit too, whoever owns it.
  • You are metered on what is stored, not what you upload. Images are converted before they are measured, so a 9 MB PNG that lands as a 1.4 MB WebP costs you 1.4 MB. The file-size limit applies to the converted result.
  • Delivery is never blocked by storage. Passing your quota stops new uploads. Content already published keeps serving.

Per asset

Text lengthUp to 5,000 characters. Configurable per asset between 5 and 5,000.
HTML length 100,000 characters — roughly 100 KB, and about three times a 5,000-word article, so long-form content belongs in an HTML asset. You can declare a lower ceiling per asset to stop an editor pasting something enormous.
JSON length50,000 characters
Version history — images10 versions retained
Version history — text, HTML, JSON50 versions retained

Older versions are trimmed automatically once the limit is passed. Images retain fewer because each version keeps its own stored files.

Image variants

Every image asset returns an object of URLs. The sizes are maximum widths — aspect ratio is always preserved, so the height follows your source image.

VariantMax width
originalAs uploaded, after conversion
large1200 px
medium800 px
thumb400 px

Not every variant always exists.

Variants are never upscaled, so a 500 px upload has no large. GIF and SVG return original only, to keep animation and vector data intact. Fall back to original when the variant you want is absent.

Rate limits

Exceeding a limit returns 429 with a message naming which one you hit. Rate-limited requests are not counted against your quota.

The monthly request limit applies to free and trial plans only. Paid plans are unmetered — there is no monthly ceiling and no overage charge. If you see Monthly API request limit reached for this project on a paid plan, that is a bug worth reporting.

Caching and freshness

  • Publishing takes effect immediately. The cache is invalidated on publish, so the next request returns the new content. You never wait out a timer to see a change go live.
  • Otherwise responses are cached for 5 minutes. That is the ceiling on how stale a response can be when nothing has been published.
  • Check X-Duggie-App-Cache on the response to see whether you were served from cache. Preview-token requests bypass the cache entirely, so a draft is always current.
  • Cached responses still count against your monthly requests. The cache protects response times, not your allowance. If you are fetching per page view on the free tier, cache on your own side too — 5,000 a month is roughly 160 views a day.

What the API does and doesn't do

The public API has two endpoints: read your content, and write it in bulk. If you think we should support others, please submit a features request through the contacts page.

No publish webhooks yet

Duggie assumes you fetch content at request time, so there is nothing to notify. If you build statically — Next.js SSG, Astro, Hugo — there is currently no way to trigger a rebuild when a client publishes; you would rebuild on a schedule instead. Worth knowing before you choose an architecture, and worth telling us if it is blocking you.

Batch writes

Assets per request1 to 100
Tag lengthUp to 200 characters
Types acceptedText, JSON, HTML. Images are uploaded separately.
  • One item with bad content does not fail the batch. Content that breaks a rule is skipped and the rest are applied: invalid JSON, HTML or text over its length limit, or a value that breaks one of the asset's own field rules. The response is 200 with a per-item result, so check the body rather than the status code to know what landed.
  • A malformed request is rejected whole. An item missing its tag or content is a bad request rather than a bad row, so the call answers 400 and nothing is written. Fix the payload and send it again.
  • Creation stops at your asset limit. A batch that would take you past it creates what fits and skips the rest, rather than rejecting the whole call. Updates to existing assets are unaffected.
  • Asset type is fixed at creation. Sending a different type for an asset that already exists does not change it; the existing type wins.