Skip to main content
These are current platform defaults, not fixed constants — contact customer.success@kardinal.ai to raise any of them for your account.

Reaching a limit (403)

A 403 with code: NOT_ALLOWED usually signals that an agency limit was reached. There are three limits, and the properties.details field of the error states which one applies:
  • Optimization quota. Once an agency’s daily or monthly optimization quota is reached, further requests fail. A restart with PUT /plans/{planId}/running (body true) counts as one optimization too.
  • Plan size limit. A plan that exceeds one of the per-plan limits in the preceding table (resources, orders, stops, or stops per order without successiveStops) is rejected.
  • Insufficient credits. In production, a request that would consume more credits than your balance has left is rejected. See Pricing and credits.
Two other situations return the same 403 NOT_ALLOWED, and neither is a limit:
  • A revoked or regenerated token. A token revoked or regenerated in the Console gets a 403 with code: NOT_ALLOWED and properties.details set to the token is invalid, on every endpoint, reads and DELETE included. It isn’t a 401: only a missing, malformed, or expired token gets a 401.
  • An archived plan. An archived plan (one with archivedAt set) refuses an update (PUT /plans/{planId}), and a stop or a restart (PUT /plans/{planId}/running), with a 403 NOT_ALLOWED whose properties.details reads Cannot update an archived plan, except with the 'force' query param. Add ?force=true to unarchive it. On an archived plan, PUT /plans/{planId}?force=true always creates a new version and re-optimizes the plan, even if its content is identical. An archived plan is more than 24 hours old, so a forced update or restart bills every stop again (see Pricing and credits). On a plan that isn’t archived, force has no effect. Don’t set it by default.
The error comes in the same EnvelopedErrors envelope as any other business error. See the Error schema. A plan size limit returns one INVALID_VALUE error per exceeded limit, each naming the field in properties.path (for example resources or orders.stops) and the exceeded limit in properties.details, followed by a single NOT_ALLOWED stating that the plan violates the agency’s quota configuration. Read every error in the response, not only the first:

Temporary overload (429)

A 429 response signals a temporary overload rather than a quota: no server was available to take the request. It comes with an empty body and no Retry-After header. Retry after a pause, with an increasing delay between attempts, and avoid sending large bursts of simultaneous requests.

Max computation time

You control how long a plan can optimize with the plan-level maxOptimizationDuration field (see How the optimization engine works), within your agency’s maximum: 5 seconds for the sandbox, 6 hours for production by default. A longer value is clamped to that maximum, and the response to the POST or PUT carries a warning saying so — warnings are only returned in that response, never by a later GET, so read them there. If the field is omitted, the default applies: 5 seconds for the sandbox, 15 minutes for production. The engine stops earlier on its own once it stops finding improvements. Contact customer.success@kardinal.ai if your production agency needs a longer maximum. The one indirect limit on computation time is throughput, not duration: if your agency already has its maximum number of simultaneous running plans in progress (10 by default), a new plan waits in the waiting room (status.waitingRoom) until a slot frees up, before its own maxOptimizationDuration clock effectively starts mattering. Contact customer.success@kardinal.ai if your account needs a higher threshold.

Payload size in practice

There’s no explicit byte-size limit on a submitted plan, but it’s bounded in practice by the ~16 MB storage limit of the document it’s stored as internally — an order of magnitude, not an exact JSON byte cap. The per-plan object counts in the preceding table (orders, stops, resources) are the limits to design against.

SLA

Kardinal targets 99.9% uptime as an internal objective, but this is not currently a contractual uptime commitment — no formal availability guarantee is offered for API access today. Support response times, on the other hand, are defined by severity: Report an issue to customer.success@kardinal.ai and state its severity to get the applicable response time.

See also

  • How the optimization engine works — the quality-vs-time trade-off and the status lifecycle (waitingRoom, creation, optimization, waitingTraffic).
  • Handling large volumes — practical guidance for sizing maxOptimizationDuration and paginating large result sets.
  • Pricing and credits — credit consumption, counted separately from the optimization quota, although insufficient credits return the same 403.