Concurrency & Rate Limits
Concurrency key
Limit how many instances with the same key run simultaneously. Prevents running two campaigns for the same contact at once.
{
"concurrency_key": "contact:john@acme.com",
"max_concurrency": 1
}Instances that exceed max_concurrency are deferred until a slot opens — they are never dropped.
Idempotency key
Prevent duplicate instance creation. If an instance with the same key already exists, the API returns the existing instance ID and "deduplicated": true.
{
"idempotency_key": "signup:user-12345:2024-01-15"
}Rate limiting
Per-resource sliding window, scoped by tenant. Overages are deferred — rescheduled to the next available slot, never dropped or failed.
// Set on the step that should be rate-limited
{
"type": "step",
"handler": "http_request",
"params": { "url": "https://api.example.com/send", "method": "POST" },
"rate_limit_key": "mailbox:outreach@acme.com"
}
// Rate limit configuration (created via API or config)
{
"resource_key": "mailbox:outreach@acme.com",
"max_count": 30,
"window_seconds": 86400
}Rate limit checks are atomic — a single database round-trip. Multiple scheduler nodes share the same rate limit counters via PostgreSQL.