Appearance
Rate limits and quotas
Every number on this page is a deployment setting shown with its default, not a product limit. They are abuse guards, set far above what a real integration needs. Nothing here is a reason to redesign an integration; if you are close to one, ask us.
Status
The REST limits below ship with the Business API. The webhook delivery numbers are live today.
The REST API
| Limit | Default | Deployment setting |
|---|---|---|
| API keys per shop | 10 | API_KEY_MAX_PER_SHOP |
| Requests per minute, per key | 300 | API_KEY_RATE_LIMIT_PER_MINUTE |
| Maximum page size | 100 items | PUBLIC_API_MAX_PAGE_SIZE |
| Idempotency-Key retention | 24 hours | IDEMPOTENCY_DEDUPE_WINDOW_HOURS |
| Overlap when a key is rotated | 24 hours | CREDENTIAL_ROTATION_GRACE_HOURS |
Every value above is a deployment setting with the default shown, not a product limit, and every one of them is an abuse guard set far above what a real integration needs. If yours needs more, ask — it is a configuration change, not a release.
The rate limit is per key, not per shop. That is deliberate: one runaway integration must not be able to lock out a working one. The consequence is actionable — if you run a nightly bulk sync and a live provisioning flow, give them separate keys and the bulk job cannot starve the interactive one.
When you are limited
http
HTTP/1.1 429 Too Many Requests
Retry-After: 12
Content-Type: application/json
{ "error": { "code": "rate_limited", "message": "Rate limit exceeded", "request_id": "req_01J9…" } }Honour Retry-After, and retry with the same Idempotency-Key. The integration kit has this loop written and tested in three languages, including the part people get wrong (a fresh key per attempt is not a retry — it is a second write).
Webhook delivery
| Limit | Default | Deployment setting |
|---|---|---|
| Webhooks per shop | 50 | WEBHOOK_MAX_PER_SHOP |
| Delivery attempts per event | 5 | lib/queues.ts (shared queue defaults) |
| Backoff between attempts | exponential from 5s | lib/queues.ts |
| Request timeout | 10000 ms | WEBHOOK_DELIVERY_TIMEOUT_MS |
| Consecutive failures before a webhook is auto-disabled | 15 | WEBHOOK_MAX_CONSECUTIVE_FAILURES |
| Delivery-log retention | 30 days | WEBHOOK_DELIVERY_RETENTION_DAYS |
| Custom headers per webhook | 20 | WEBHOOK_MAX_CUSTOM_HEADERS |
| Custom headers, total size | 4096 bytes | WEBHOOK_CUSTOM_HEADERS_MAX_BYTES |
Custom headers and per-shop fan-out budgets ship with the shop-scoped webhook update; see Webhooks.
The MCP connector
| Limit | Default | Deployment setting |
|---|---|---|
| MCP keys per shop | 5 | MCP_KEY_MAX_PER_SHOP |
| Calls per minute, per key | 60 | MCP_KEY_RATE_LIMIT_PER_MINUTE |
| Calls per day, per key | 5000 | MCP_KEY_DAILY_CALL_BUDGET |
The per-minute limit bounds a spike; the daily budget bounds a loop that runs all night. An agent loop is a different traffic shape from a nightly CRM sync, and a runaway loop is its normal failure mode rather than an exceptional one — which is also why these limits are tighter than the REST API's.
What the plan costs
Nothing about pricing is written on this page on purpose — a price typed into a document is a price that goes stale. Current prices come from one place:
bash
curl -s https://api.tesserapp.eu/api/v1/pricingSee Plan limits for what the integration module includes.