Skip to main content
A plan is the problem you submit: resources (vehicle-driver pairs), orders (each grouping one or more stops), and optional constraints and objectives. The SDKs don’t add a modeling layer of their own: their models are generated from the API’s OpenAPI specification, field for field. This page covers how to build a plan in code; what each field means is documented once, in the API Reference and the Data model.

Typed models and the API spec

Models are pydantic classes, under kardinal.routing.models (Resource, SingleStop, Position, TimeWindow, and every other schema of the spec). PlanCreate and Order come from kardinal.routing.plans. A model refuses a misspelled key and a value of the wrong type as soon as you build it.
Field names keep the API’s camelCase in both languages (workingTimeWindow, operationDuration): what you write is what the API receives. Only method and argument names follow each language’s convention, such as plans.get_status in Python and plans.getStatus in TypeScript.

PlanCreate and Plan

Two shapes describe a plan, as in the API:
  • PlanCreate is what you submit. It has no id: the server assigns one. Setting id yourself is refused before sending.
  • Plan is what submit, get, and update return: the same content plus the fields the server manages (id, version, status, state, agencyId). To change a plan, modify the Plan you read and pass it to update.
A plan has no top-level list of stops: stops live inside Order.stops, and Plan.orders is the list of orders. An order groups the stops that must be served by the same resource, such as a pickup and its delivery.

Starting from the example plan

The fastest way to a valid plan is to adapt the example both SDKs ship: two resources, eight single-stop orders, and a 10-second optimization. Each call returns a fresh plan you can modify freely.
The example’s working window starts tomorrow at 8:00, computed when you call it, so the plan never refers to a date already past.

Loading an existing JSON payload

If you already have a plan as JSON — exported from your own system, written by hand, or copied from a modeling example — load it into the SDK’s model rather than rebuilding it:
Loading runs the same checks as submit: a missing required field, a wrong type, or a misspelled key fails here, with its path in the plan, before anything is sent.

Validating locally before you spend credits

Every check below runs on your machine, with no API call and no credits:
  • Structure and types: building a Python model, or parsePlanCreate in TypeScript, fails on a missing required field or a value of the wrong type.
  • Unknown keys: submit refuses a key no model declares, and lists each one with its path and the closest real field name. To run that check yourself before sending, call unknown_fields(plan) (Python, from kardinal.routing) or unknownFields(plan) (TypeScript).
  • A plan file: kardinal routing plans validate plan.json runs both checks on a JSON file, from a shell or a CI job — see Local validation.
These checks catch mistakes in the shape of the plan. They don’t check its business consistency: whether the fleet can carry the total demand, or whether a time window is reachable, is the engine’s call, and shows up in the solution as unplanned stops. See Handling infeasibility. The two SDKs differ in the depth of their checks:
Every object of the plan is checked, including the rarer nested ones (cost, breaks, objectives, constraints). pydantic accepts a string holding a number or a boolean, such as "1" or "true", and converts it.

Where field documentation lives

The API Reference is the reference for every field: its meaning, unit, default, and constraints. The SDKs carry the same descriptions, generated from the same specification, so your editor shows them on hover. If the two ever disagree, the API Reference is right: report it as an issue on the SDK’s repository.

Using the SDKs with AI coding agents

An agent writing integration code gets the most out of the typed models: wrong field names and types fail fast, with the exact path, instead of producing a valid but wrong plan.
  • Run kardinal init in your project: it writes .kardinal/SKILL.md, a short pointer that tells a coding assistant the SDK is there and how to call it.
  • Point the agent at the AI agent modeling checklist before it models your operation.
  • Have it validate every payload locally, with the checks on this page, before submitting anything with a production key.