Plan limits
Each DuckHub plan caps how many menu items a venue can hold. Syncs that would create more items than your plan allows are rejected before anything is written.
Plan availability
API keys and the Menu API are available on every plan, including the free Egg plan. Only the Orders API requires a paid plan.
Limits per venue#
| Egg (free) | Duckling | Golden Duck | |
|---|---|---|---|
| Products | 70 | 2000 | 2000 |
| Categories | 10 | 200 | 200 |
| Ingredients | 300 | 300 | 300 |
The counts are per venue and include everything already in the menu — a
sync fails if existing items + new items in the request would exceed the
cap. Updating existing items (matched by externalId) never counts against
the limit; only new items do.
Per-request array caps#
Independent of plan limits, one POST /v1/sync request accepts at most:
| Array | Max per request |
|---|---|
categories | 200 |
ingredients | 200 |
products | 500 |
Larger catalogs should be split into several sequential sync requests
(mind the rate limits). Exceeding an array cap is a
400 validation error.
When a limit is exceeded#
The sync fails with 400 Bad Request and no changes are applied — the
request is checked up-front, so a rejected sync never leaves the menu
half-updated.
Machine-readable limit errors
Plan-limit rejections carry a code field:
CATEGORY_BULK_LIMIT_EXCEEDED,
INGREDIENT_BULK_LIMIT_EXCEEDED or
PRODUCT_BULK_LIMIT_EXCEEDED — branch on it instead of
parsing messages. See Errors.
They also carry a details object with the exact headroom, so you can
resize the batch without another round-trip:
{
"statusCode": 400,
"message": "Bad Request Exception",
"code": "PRODUCT_BULK_LIMIT_EXCEEDED",
"details": { "limit": 70, "available": 12, "requested": 50 },
"requestId": "8f14e45f-ceea-4671-a2d5-6d5c9a3f1b2e",
"timestamp": "2026-07-05T12:00:00.000Z",
"path": "/v1/sync"
}To free up capacity, delete stale products with
DELETE /v1/products/:ref
— or upgrade the plan in the DuckHub app. Note that
POST /v1/cleanup only hides products
(menuVisible: false); hidden products still count toward the limit.
Deleted categories and ingredients (cleanup deletes those for real) free
their counters immediately.