Rate limits and quotas
This page documents the operational limits an API client should design around. Some values are environment-configurable, so client code should read response errors and headers instead of hard-coding every number.
Request rate limiting
The default API rate limit is:
120 requests per 60 seconds
The backend reads these environment variables:
| Setting | Default | Meaning |
|---|---|---|
RATE_LIMIT_ENABLED |
true |
Enables request rate limiting. |
RATE_LIMIT_REQUESTS_PER_MINUTE |
120 |
Requests allowed per bucket window. |
RATE_LIMIT_WINDOW_SECONDS |
60 |
Window size in seconds. |
RATE_LIMIT_BACKEND |
auto |
Uses Redis when configured, otherwise memory. |
RATE_LIMIT_REQUIRE_REDIS |
production dependent | Fails startup/readiness if Redis is required but unavailable. |
When rate limited, clients receive:
429 Too Many Requests
Clients should back off using the retry hint returned by the deployment when available. If no header is present, use exponential backoff with jitter.
Pagination limits
Entity browsing uses bounded pagination:
/api/v1/demo-jobs/{job_ref}/entities/{entity}GET /api/v1/demo-jobs/{job_ref}/entities/{entity}?limit=100&offset=0
Current maximum page size:
1000 records
Clients should page until:
offset + data.length >= count
Do not assume that a single page can contain a full ledger.
Partner bundle limit
The normalized bundle endpoint is capped so one response cannot accidentally ship an entire large tenant through a JSON response.
Default:
PARTNER_BUNDLE_MAX_RECORDS=25000
Endpoint:
/api/v1/demo-jobs/{job_ref}/bundleGET /api/v1/demo-jobs/{job_ref}/bundle
If the selected entities exceed the cap:
413 Payload Too Large
{
"detail": "Bundle too large for one response. Requested 30001 records across 15 entities, which exceeds the partner bundle cap of 25000. Use the entity or export endpoints instead."
}
The cap can be changed by deployment configuration. Treat 413 as a signal to
page or export, not as a numeric limit to hard-code into a client.
Recovery options:
- request fewer entities with repeated
entityquery params - use paginated entity reads
- use per-entity exports
- use the runtime CSV export pack route when the use case is "download all data"
Dataset storage limits
The current project dataset blob model has write-time guardrails.
Defaults:
| Setting | Default |
|---|---|
FICTIX_MAX_PROJECT_DATASET_RECORDS |
300000 |
FICTIX_MAX_PROJECT_DATASET_BYTES |
134217728 |
If a write would exceed the dataset budget, the API returns a structured error:
{
"detail": {
"code": "project_dataset_limit_exceeded",
"project_id": "proj_123",
"context": "simulation_step",
"record_count": 315000,
"max_records": 300000,
"estimated_bytes": 140000000,
"max_bytes": 134217728,
"message": "Project dataset exceeds current blob storage safety budget"
}
}
Client action:
- reduce generated scale
- clone into smaller scenario-specific jobs
- avoid long unbounded simulation runs
- export and archive data before destructive reset if needed
Generation admission limits
Fictix estimates generation load before doing expensive work.
Default generation budget:
MAX_WEIGHTED_GENERATION_LOAD=300000
Weighted load is roughly:
estimated_records * quality_multiplier * connector_multiplier
Quality multipliers:
| Quality preset | Multiplier |
|---|---|
clean |
1.0 |
realistic |
1.1 |
messy |
1.25 |
stress_test |
1.5 |
Connector multiplier:
1 + max(0, connector_count - 1) * 0.25
Full system materialization uses at least 6 connector-equivalent units.
If a request is too large:
422 Unprocessable Entity
{
"detail": "Requested generation load exceeds the server budget (420,000 weighted units for about 145,000 estimated records, quality 'realistic', 8 connectors; budget 300,000). Reduce employees, months_of_history, customers_per_employee, or connector breadth. With the current shape, try <= 85 employees or <= 12 months_of_history."
}
Client action:
- lower
generation.employees - lower
generation.months_of_history - reduce
customers_per_employee - select fewer services
- use
cleanfor broad smoke tests - create multiple smaller demo jobs instead of one huge tenant
Webhook limits
Webhook subscription limits:
| Limit | Value |
|---|---|
| Active subscriptions per org | 20 |
| Event filters stored per subscription | 50 |
| Delivery worker batch size | 100 |
| Synchronous POST attempts | 3 |
Webhook delivery is billed/metered as webhook_deliveries when quota is
configured for the project.
Plan quotas
Plan-level quotas are enforced from the billing catalog. The signed-in Fictix Console is the customer-facing source of truth for an organization's active plan and current usage; do not infer entitlement from a key name or a documentation table alone.
Current default catalog limits:
| Plan | Test runs/mo | API units/mo | Scenario runs/mo | Events/mo | Storage | Webhook deliveries/mo |
|---|---|---|---|---|---|---|
| Starter | 25 | 10,000 | 100 | 100,000 | 500 MB | 0 |
| Hobbyist | 100 | 25,000 | 250 | 250,000 | 1 GB | 0 |
| Developer | 500 | 100,000 | 5,000 | 2,000,000 | 10 GB | 25,000 |
| Pro | 2,500 | 500,000 | 25,000 | 10,000,000 | 50 GB | 100,000 |
| Enterprise | 10,000 | 2,500,000 | 100,000 | 50,000,000 | 100 GB | 250,000 |
When quota is exhausted, clients should stop the workflow or surface an upgrade path. Do not auto-retry quota failures. Use the Console to review usage and upgrade eligibility.
Client backoff policy
Recommended general policy:
| Response | Retry? | Policy |
|---|---|---|
429 |
Yes | Respect retry hint; otherwise exponential backoff with jitter. |
500 |
Sometimes | Retry idempotent operations only. |
503 |
Yes | Back off and recheck readiness. |
409 |
No | Resolve idempotency conflict or active-operation conflict. |
413 |
No | Page or use exports instead. |
422 |
No | Fix request shape or reduce scale. |
/api/v1/demo-jobs
For POST /api/v1/demo-jobs, retry only with the same request body and same
Idempotency-Key.
