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:

GET/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:

GET/api/v1/demo-jobs/{job_ref}/bundle
GET /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 entity query 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 clean for 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.
POST/api/v1/demo-jobs

For POST /api/v1/demo-jobs, retry only with the same request body and same Idempotency-Key.