kardinal-ai 1.0.0. Install it with pip install kardinal-ai, import it as kardinal. Every method below is synchronous. Field-level documentation for plans and solutions lives in the API Reference.
Client
Kardinal
The methods hang off
k.routing.plans and k.routing.solutions. The client holds an httpx connection pool: use it as a context manager (with Kardinal() as k:) or call k.close(). See Client configuration.
Plans
plans.submit
POST /plans. Creates the plan and starts its optimization. Returns the stored Plan, with the id the server assigned and .warnings. Raises UnknownFieldError, before sending, for a key no model declares, unless named in allow_unknown. Consumes credits with a production key. Never retried.
plans.get
GET /plans/{planId}. Returns the plan as currently stored. Raises KardinalNotFoundError if it doesn’t exist.
plans.update
PUT /plans/{planId}. Replaces the whole plan: anything left out is removed. The version increments, and the plan is re-optimized, only if the content changed; an identical update is a free no-op. Fields unknown to this SDK version that get read are sent back untouched; a key you added that no model declares raises UnknownFieldError, unless named in allow_unknown. On a plan not read from the API, a likely typo only emits an UnknownFieldWarning. force=True unarchives an archived plan first. Retried.
plans.delete
DELETE /plans/{planId}. Permanently deletes the plan and its solution, and stops any optimization in progress. Retried.
plans.list
GET /plans. Returns one page of plans, in their light form. A page past the last one returns the last page.
plans.iter_all
GET /plans, every page. Iterates over every plan, fetching pages as it goes.
plans.start
PUT /plans/{planId}/running. Restarts the optimization of the current version, without changing its content or version. Returns agencyId, planId, planVersion, and warnings. Retried.
plans.stop
PUT /plans/{planId}/running. Stops the optimization in progress, without changing the plan’s content or version. Retried.
plans.get_status
GET /plans/{planId}/state. Returns the plan’s current state, a single value: waiting, processing, optimizing, optimized, stopped, interrupted, and so on. A state this SDK version doesn’t know comes back as its raw string. Not the detailed PlanStatus object found in Plan.status.
Solutions
solutions.wait
GET /plans/{planId}/state, then /solution. Blocks until the optimization of the current version is over, then returns its solution. Reads the state every 10 seconds at first, up to every 60 seconds. solution.final_state tells how it ended: optimized, interrupted, or stopped. Raises KardinalOptimizationError (NO_SOLUTION, PLAN_SUPERSEDED, OPTIMIZATION_STALLED), KardinalNotFoundError if the plan is deleted meanwhile, and KardinalTimeoutError once timeout seconds have elapsed. See Waiting for the solution.
solutions.get
GET /plans/{planId}/solution. Returns the current best solution right away, without waiting. Raises KardinalNotFoundError until the engine has a first solution.
solutions.get_objectives
GET /plans/{planId}/solution/objectives. Returns the value of each objective, without the tours: a plain list of SolutionObjective, with a .warnings attribute.
Examples
examples.small_delivery_plan
Local checks
unknown_fields
submit makes, without sending anything: every key no model declares, with its path and, when one is close, the real field name it was likely meant to be. Empty when the plan is clean.
Types
PlanCreate
From kardinal.routing.plans. The plan you submit: no id, the server assigns it. Built from kardinal.routing.models objects, or loaded from JSON with PlanCreate.model_validate_json(text). Its orders are kardinal.routing.plans.Order objects.
Plan
From kardinal.routing.plans. The plan as stored, returned by submit, get, and update: the same content plus id, version, status, state, and agencyId, and .warnings from the call that returned it.
Page
From kardinal. Returned by plans.list: items, page, total_pages, total, next_page (None on the last page), previous_page (None on the first page), and items_per_page.
Model types
kardinal.routing.models holds a pydantic model for every schema of the API specification (Resource, SingleStop, AlternativesStop, Position, TimeWindow, Solution, Tour, Warning, and so on), with the API’s field names and descriptions.
Exceptions
All importable fromkardinal, all subclasses of KardinalError. See Errors, retries, and warnings.
UnknownFieldWarning, also importable from kardinal, is a warning, not an exception: see Client-side errors.
Every exception carries .code, .status, .errors, .details, .retryable, .warnings, and .request_id.
Known limitations
- The client is synchronous; there’s no
asyncioclient. pydanticconverts a string holding a number or a boolean ("1","true") instead of refusing it..request_idis usuallyNone: the API sends anX-Request-Idheader only on some responses.- The
kardinalcommand needs thecliextra:pip install "kardinal-ai[cli]".

