> ## Documentation Index
> Fetch the complete documentation index at: https://developers.kardinal.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK quickstart

> Install the Kardinal Python or TypeScript SDK, set your API key, submit the built-in example plan, and read its optimized tours in a few lines of code.

This page takes you from an empty project to an optimized route with the SDK of your choice. It uses the example plan shipped with both SDKs: two vehicles and eight deliveries around central Paris.

## Before you start

You need:

* **An API key.** Sign up on the [Console](https://console.kardinal.ai) and generate a key for your `sandbox` agency — see [Authentication and API keys](/guides/authentication). A sandbox key consumes no credits, which makes it the right key for this page.
* **A runtime.** Python 3.10 or later, or Node.js 22 or later.

## Installing the package

<CodeGroup>
  ```bash Python theme={null}
  pip install kardinal-ai
  ```

  ```bash TypeScript theme={null}
  npm install @kardinal-ai/sdk
  ```
</CodeGroup>

The Python package installs as `kardinal-ai` and imports as `kardinal`. See [Installation](/sdks/installation) for the `kardinal` command-line tool and the module formats.

## Setting your API key

Both SDKs read the key from the `KARDINAL_API_KEY` environment variable:

```bash theme={null}
export KARDINAL_API_KEY="<your sandbox API key>"
```

Keep the key out of your source code. [Client configuration](/sdks/configuration) covers the other ways to pass it.

## Submitting the example plan

<CodeGroup>
  ```python Python theme={null}
  from kardinal import Kardinal
  from kardinal.routing import examples

  k = Kardinal()  # reads KARDINAL_API_KEY
  plan = k.routing.plans.submit(examples.small_delivery_plan())
  solution = k.routing.solutions.wait(plan.id)  # returns in about 20 seconds
  ```

  ```ts TypeScript theme={null}
  import { Kardinal, examples } from "@kardinal-ai/sdk";

  const k = new Kardinal(); // reads KARDINAL_API_KEY
  const plan = await k.routing.plans.submit(examples.smallDeliveryPlan());
  const solution = await k.routing.solutions.wait(plan.id); // resolves in about 20 seconds
  ```
</CodeGroup>

`submit` sends the plan, which starts its optimization, and returns it with the `id` the server assigned. `wait` follows the optimization and returns the solution once it's over.

The example plan asks for a 10-second optimization. The sandbox caps optimizations at 5 seconds, so `submit` returns a warning saying the duration was clamped: that's expected, and `plan.warnings` lists it.

## Reading the result

<CodeGroup>
  ```python Python theme={null}
  print(solution.final_state)  # optimized, or interrupted/stopped if cut short
  for tour in solution.tours or []:  # tours is None when no stop could be planned
      print(tour.resourceId, len(tour.wayPoints))
  ```

  ```ts TypeScript theme={null}
  console.log(solution.finalState); // optimized, or interrupted/stopped if cut short
  for (const tour of solution.tours ?? []) {
    // tours is absent when no stop could be planned
    console.log(tour.resourceId, tour.wayPoints?.length);
  }
  ```
</CodeGroup>

Each tour is the route of one resource, as a list of waypoints. The final state says how the optimization ended: check it before treating the result as final. See [Retrieve a plan solution](/api-reference/solution/retrieve-a-plan-solution) in the API Reference for every field of the solution.

### Why `wait` rather than `get`

The API is asynchronous. Right after `submit`, the plan is still waiting or being processed: `solutions.get` then fails with a `404`, and a moment later returns whatever the engine has found so far, which can be empty or incomplete. `wait` returns only once the optimization is over.

## Next steps

* [Building plans with typed models](/sdks/building-plans): describe your own fleet and orders, or load a JSON payload you already have.
* [Plan lifecycle](/sdks/plan-lifecycle): re-optimize after a change, track a plan without blocking, and list or delete plans.
* [Errors, retries, and warnings](/sdks/errors-and-warnings): handle validation errors, limits, and quotas.
* [Moving from sandbox to production](/guides/sandbox-to-production): what changes when you switch to a production key.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.