@kardinal-ai/sdk 1.0.1, for Node.js 22 or later. Every method below returns a Promise, except plans.iterAll, an async iterator. 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. There’s nothing to close. See Client configuration.
Plans
plans.submit
POST /plans. Validates the plan locally, then creates it and starts its optimization. Returns the stored Plan, with the id the server assigned and warnings. Throws a ZodError for an invalid plan, and UnknownFieldError for a key no schema declares unless named in allowUnknown, both before sending. Consumes credits with a production key. Never retried.
plans.get
GET /plans/{planId}. Returns the plan as currently stored. Rejects with 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 schema declares throws UnknownFieldError, unless named in allowUnknown. On a plan this client didn’t read, a likely typo only goes to onWarning. 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; defaults: page 1, 20 items, archived plans excluded. A page past the last one returns the last page.
plans.iterAll
GET /plans, every page. Iterates over every plan with for await, 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.getStatus
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. Resolves once the optimization of the current version is over, with its solution. Reads the state every 10 seconds at first, up to every 60 seconds. solution.finalState tells how it ended: optimized, interrupted, or stopped. Rejects with KardinalOptimizationError (NO_SOLUTION, PLAN_SUPERSEDED, OPTIMIZATION_STALLED), KardinalNotFoundError if the plan is deleted meanwhile, and KardinalTimeoutError once timeoutMs milliseconds have elapsed. See Waiting for the solution.
solutions.get
GET /plans/{planId}/solution. Returns the current best solution right away, without waiting. Rejects with KardinalNotFoundError until the engine has a first solution.
solutions.getObjectives
GET /plans/{planId}/solution/objectives. Returns the value of each objective, without the tours: a plain array of SolutionObjective, with a warnings property.
Examples
examples.smallDeliveryPlan
Local checks
unknownFields
submit makes, without sending anything: every key no schema 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.
parsePlanCreate(data, allowUnknown?) runs all of submit’s local checks, zod validation included, and returns the plan with its defaults applied; parsePlan(data) validates a stored plan, such as one read from a file before an update.
Types
PlanCreate
The plan you submit: no id, the server assigns it. PlanCreateInput is the same shape before defaults are applied: the type to use for a plan you build by hand.
Plan
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
Returned by plans.list: items, page, totalPages, total, nextPage (null on the last page), previousPage (null on the first page), and itemsPerPage.
Model types
The package exports a type 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. Import them with import type.
Exceptions
All importable from@kardinal-ai/sdk, all subclasses of KardinalError. See Errors, retries, and warnings.
A plan that fails local validation throws a
ZodError, from zod, instead.
Every error carries .code, .status, .errors, .details, .retryable, .warnings, and .requestId.
Known limitations
- Node.js only: browsers aren’t supported.
- The inside of the rarer nested objects (
cost,breaks,objectives, constraints) isn’t validated locally, and a misspelled key there isn’t reported. update’s exact check of unknown keys needs the plan to have been read by the same client, in the same process; it remembers the last 64 plans..requestIdis usuallynull: the API sends anX-Request-Idheader only on some responses.- The
kardinalcommand needscommanderinstalled alongside the package.

