# Redis Intent Router quickstart

```json metadata
{
  "schema_version": 2,
  "title": "Redis Intent Router quickstart",
  "description": "Define two intents, match queries against them, and update an intent with Python, TypeScript, HTTP, or the Iris CLI.",
  "categories": ["docs","develop","ai"],
  "tableOfContents": {"sections":[{"id":"before-you-begin","title":"Before you begin"},{"id":"save-connection-values","title":"Save connection values"},{"id":"connect-to-the-router","title":"Connect to the Router"},{"id":"create-intents","title":"Create intents"},{"id":"match-a-query","title":"Match a query"},{"id":"add-an-example","title":"Add an example"},{"id":"change-an-intents-threshold","title":"Change an intent's threshold"},{"id":"clean-up","title":"Clean up"},{"id":"next-steps","title":"Next steps"}]}

,
  "codeExamples": [{"codetabsId":"iris_intent_router_quickstart-steprouter-connect","difficulty":"beginner","id":"router-connect","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_intent_router_quickstart-steprouter-connect"},{"clientId":"iris-typescript","clientName":"TypeScript (Iris)","id":"TypeScript (Iris)","langId":"typescript","panelId":"panel_TypeScript (Iris)_iris_intent_router_quickstart-steprouter-connect"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_intent_router_quickstart-steprouter-connect"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_intent_router_quickstart-steprouter-connect"}]},{"codetabsId":"iris_intent_router_quickstart-stepintents-create","difficulty":"beginner","id":"intents-create","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_intent_router_quickstart-stepintents-create"},{"clientId":"iris-typescript","clientName":"TypeScript (Iris)","id":"TypeScript (Iris)","langId":"typescript","panelId":"panel_TypeScript (Iris)_iris_intent_router_quickstart-stepintents-create"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_intent_router_quickstart-stepintents-create"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_intent_router_quickstart-stepintents-create"}]},{"codetabsId":"iris_intent_router_quickstart-stepmatch-query","difficulty":"beginner","id":"match-query","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_intent_router_quickstart-stepmatch-query"},{"clientId":"iris-typescript","clientName":"TypeScript (Iris)","id":"TypeScript (Iris)","langId":"typescript","panelId":"panel_TypeScript (Iris)_iris_intent_router_quickstart-stepmatch-query"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_intent_router_quickstart-stepmatch-query"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_intent_router_quickstart-stepmatch-query"}]},{"codetabsId":"iris_intent_router_quickstart-stepexamples-add","difficulty":"beginner","id":"examples-add","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_intent_router_quickstart-stepexamples-add"},{"clientId":"iris-typescript","clientName":"TypeScript (Iris)","id":"TypeScript (Iris)","langId":"typescript","panelId":"panel_TypeScript (Iris)_iris_intent_router_quickstart-stepexamples-add"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_intent_router_quickstart-stepexamples-add"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_intent_router_quickstart-stepexamples-add"}]},{"codetabsId":"iris_intent_router_quickstart-stepintent-update","difficulty":"beginner","id":"intent-update","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_intent_router_quickstart-stepintent-update"},{"clientId":"iris-typescript","clientName":"TypeScript (Iris)","id":"TypeScript (Iris)","langId":"typescript","panelId":"panel_TypeScript (Iris)_iris_intent_router_quickstart-stepintent-update"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_intent_router_quickstart-stepintent-update"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_intent_router_quickstart-stepintent-update"}]},{"codetabsId":"iris_intent_router_quickstart_delete-stepintents-delete","difficulty":"beginner","id":"intents-delete","languages":[{"clientId":"iris-python","clientName":"Python (Iris)","id":"Python (Iris)","langId":"python","panelId":"panel_Python (Iris)_iris_intent_router_quickstart_delete-stepintents-delete"},{"clientId":"iris-typescript","clientName":"TypeScript (Iris)","id":"TypeScript (Iris)","langId":"typescript","panelId":"panel_TypeScript (Iris)_iris_intent_router_quickstart_delete-stepintents-delete"},{"clientId":"iris-curl","clientName":"cURL (Iris)","id":"cURL (Iris)","langId":"bash","panelId":"panel_cURL (Iris)_iris_intent_router_quickstart_delete-stepintents-delete"},{"clientId":"iris-cli","clientName":"CLI (Iris)","id":"CLI (Iris)","langId":"bash","panelId":"panel_CLI (Iris)_iris_intent_router_quickstart_delete-stepintents-delete"}]}]
}
```

## Code examples

These examples connect to Iris services using SDKs or HTTP requests with curl. Follow one language throughout each walkthrough.


Intent Router classifies each incoming user message by intent, so your application can send it to the right agent, workflow, or handler. This quickstart shows the whole loop in a few minutes. You define a `track_order` intent and a `refund` intent with example phrases, match three queries against them, then add an example and change a threshold to see how the results change.

## Before you begin

You need a Router in the `READY` state and an agent key with `write` access to it. `write` includes `read`. On Redis Cloud, [create an Intent Router](https://redis.io/docs/latest/operate/iris/intent-router/create-router) and an agent key in the console. On a self-managed deployment, see [Manage Routers](https://redis.io/docs/latest/develop/ai/context-engine/intent-router/manage-routers) to create a Router yourself. Platform teams mint agent keys as shown in [Create a Router and an agent key](https://redis.io/docs/latest/operate/iris/intent-router/self-managed/api-examples).

This walkthrough needs no agent framework or model-provider key.

Follow one tab throughout the page. The Python package and the command-line interface (CLI) require Python 3.11 or later. The TypeScript client requires Node.js 22 or later. The cURL and CLI examples use Bash and jq. To choose a client, see the [developer guide](https://redis.io/docs/latest/develop/ai/context-engine/intent-router/developer-guide#choose-a-client).

**Python and CLI**

```bash
python -m venv .venv
source .venv/bin/activate
python -m pip install 'redis-iris>=1.0.0'
```

**TypeScript**

```bash
npm install @redis-iris/intent-router
```

**cURL**

```bash
curl --version
jq --version
```

## Save connection values

Export these values in the shell where you run the examples. Use the data plane's base address, including the scheme, without the `/iris/data/v1/...` path.

```bash
export IRIS_INTENT_ROUTER_URL='<data-plane-endpoint>'
export IRIS_INTENT_ROUTER_ID='<router-id>'
export IRIS_INTENT_ROUTER_API_KEY='<agent-key>'
```

Keep keys out of source control and model prompts.

The Python examples use `IntentRouter` from the unified `redis-iris` package. `IntentRouter.from_env()` reads these variables, and its methods, such as `define`, `match`, `add_examples`, and `update`, return plain values such as `Intent` and `Matches`. The TypeScript examples pass the same values to the generated `@redis-iris/intent-router` client, whose methods take positional arguments with the request body after the path and header values, and return `{ headers, result }`. The CLI tab runs `iris intent-router` commands, which read the same variables. CLI commands use `--json` when saving a response or processing it with jq.

## Connect to the Router

Expand an example to copy the complete program. Save it as `quickstart.py`, `quickstart.mts`, `quickstart.sh` (cURL), or `quickstart.cli.sh`, then run `python quickstart.py`, `npx tsx quickstart.mts`, `bash quickstart.sh`, or `bash quickstart.cli.sh`.

**Available in:** Python (Iris), TypeScript (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
from redis_iris.intent_router import IntentRouter, Target

router = IntentRouter.from_env()
print(router.health())
```

##### TypeScript (Iris)

```typescript
import { IntentRouter } from "@redis-iris/intent-router";

function requiredEnv(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`Set ${name}`);
  return value;
}

const router = new IntentRouter({
  serverURL: requiredEnv("IRIS_INTENT_ROUTER_URL"),
  routerId: requiredEnv("IRIS_INTENT_ROUTER_ID"),
  apiKey: requiredEnv("IRIS_INTENT_ROUTER_API_KEY"),
  retryConfig: { strategy: "none" },
});
console.log((await router.getRouterHealth()).result);
```

##### cURL (Iris)

```bash
set -euo pipefail
ROUTER_API="${IRIS_INTENT_ROUTER_URL%/}/iris/data/v1/intent/routers/$IRIS_INTENT_ROUTER_ID"
curl --fail-with-body --silent --show-error \
  "$ROUTER_API/health" \
  -H "Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY" | jq .
```

##### CLI (Iris)

```bash
set -euo pipefail
iris intent-router health
```



The health check reports `ok: true` when the Router can serve. Each entry in `checks` covers one part: the Router's state, the embedding provider, the intent store, and the search index. When `ok` is `false`, the failing check's `message` says why, for example that the Router is still provisioning. Wait and retry.

## Create intents

Writing an intent with `PUT` creates it or replaces the one with the same name, so you can rerun this step. In Python this is `define`, and in the CLI it is `intents add`. This example defines `track_order` with a description, a target, and three examples, and `refund` with examples only.

**Available in:** Python (Iris), TypeScript (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
for intent in (
    router.define(
        "track_order",
        description="The customer wants to know where an order is.",
        target=Target("tool", "orders.track", {"region": "eu"}),
        examples=["where is my order", "track my package", "has my parcel shipped"],
    ),
    router.define(
        "refund",
        examples=["i want a refund", "refund my purchase", "i would like my money back"],
    ),
):
    print(intent.name, intent.example_count, intent.revision)
```

##### TypeScript (Iris)

```typescript
for (const intent of [
  await router.upsertIntent("track_order", undefined, undefined, {
    description: "The customer wants to know where an order is.",
    target: { type: "tool", ref: "orders.track", args: { region: "eu" } },
    examples: ["where is my order", "track my package", "has my parcel shipped"],
  }),
  await router.upsertIntent("refund", undefined, undefined, {
    examples: ["i want a refund", "refund my purchase", "i would like my money back"],
  }),
]) {
  console.log(intent.result.name, intent.result.exampleCount, intent.result.revision);
}
```

##### cURL (Iris)

```bash
curl --fail-with-body --silent --show-error \
  -X PUT "$ROUTER_API/intents/track_order" \
  -H "Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{
    "description": "The customer wants to know where an order is.",
    "target": {"type": "tool", "ref": "orders.track", "args": {"region": "eu"}},
    "examples": ["where is my order", "track my package", "has my parcel shipped"]
  }' | jq -c '{name, exampleCount, revision}'
curl --fail-with-body --silent --show-error \
  -X PUT "$ROUTER_API/intents/refund" \
  -H "Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{"examples": ["i want a refund", "refund my purchase", "i would like my money back"]}' \
  | jq -c '{name, exampleCount, revision}'
```

##### CLI (Iris)

```bash
iris intent-router intents add track_order \
  --description "The customer wants to know where an order is." \
  --target '{"type": "tool", "ref": "orders.track", "args": {"region": "eu"}}' \
  --example "where is my order" --example "track my package" --example "has my parcel shipped"
iris intent-router intents add refund \
  --example "i want a refund" --example "refund my purchase" --example "i would like my money back"
```



Each intent reports its `exampleCount` and `revision`. The first request returns `201` because the intent is new. Repeating it returns `200` with the same intent and a new `revision`.

## Match a query

Send three queries. The response lists the closest intents, best first.

**Available in:** Python (Iris), TypeScript (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
for query in ("where is my order please", "i would like my money back", "zzz qqq"):
    best = router.match(query).best
    if best:
        print(query, "->", best.name, round(best.score, 2), best.target)
    else:
        print(query, "-> no match")
```

##### TypeScript (Iris)

```typescript
for (const query of ["where is my order please", "i would like my money back", "zzz qqq"]) {
  const { items } = (await router.match({ query })).result;
  if (items.length > 0) {
    console.log(query, "->", items[0].name, items[0].score.toFixed(2), items[0].target);
  } else {
    console.log(query, "-> no match");
  }
}
```

##### cURL (Iris)

```bash
for query in "where is my order please" "i would like my money back" "zzz qqq"; do
  curl --fail-with-body --silent --show-error \
    -X POST "$ROUTER_API/match" \
    -H "Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY" \
    -H 'Content-Type: application/json' \
    --data "$(jq -n --arg query "$query" '{query: $query}')" \
    | jq -r --arg query "$query" 'if (.items | length) > 0
        then "\($query) -> \(.items[0].name) \(.items[0].score * 100 | round / 100) \(.items[0].target | tojson)"
        else "\($query) -> no match" end'
done
```

##### CLI (Iris)

```bash
for query in "where is my order please" "i would like my money back" "zzz qqq"; do
  iris intent-router match "$query"
done
```



The first query matches `track_order` and returns the target you stored. Your application reads `target.type` and `target.ref` to decide what to call. The second matches `refund`. The third, nonsense text, returns an empty list because no intent is close enough. An empty list is a successful `200` response.

Scores vary with the Router's embedding model. If a query you expect to match returns nothing, add an example rather than lowering the threshold.

## Add an example

Add a phrasing to an existing intent.

**Available in:** Python (Iris), TypeScript (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
for example in router.add_examples("track_order", ["when will my delivery arrive"]):
    print(example.example_id, example.text)
```

##### TypeScript (Iris)

```typescript
const added = await router.addExamples("track_order", {
  examples: ["when will my delivery arrive"],
});
for (const example of added.result.items) console.log(example.exampleId, example.text);
```

##### cURL (Iris)

```bash
curl --fail-with-body --silent --show-error \
  -X POST "$ROUTER_API/intents/track_order/examples" \
  -H "Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{"examples": ["when will my delivery arrive"]}' | jq -c '.items[] | {exampleId, text}'
```

##### CLI (Iris)

```bash
iris intent-router examples add track_order "when will my delivery arrive"
```



The next match uses the new example. Adding a phrasing that already exists is harmless.

## Change an intent's threshold

Updating an intent with `PATCH` changes its configuration without touching or re-embedding its examples. An omitted field is unchanged, and `null` clears a field. In Python, `update` sends only the fields you pass, and `None` clears one.

**Available in:** Python (Iris), TypeScript (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
updated = router.update("track_order", min_score=0.8)
print(updated.name, updated.min_score, updated.revision)
```

##### TypeScript (Iris)

```typescript
const { result: updated } = await router.updateIntent("track_order", undefined, { minScore: 0.8 });
console.log(updated.name, updated.minScore, updated.revision);
```

##### cURL (Iris)

```bash
curl --fail-with-body --silent --show-error \
  -X PATCH "$ROUTER_API/intents/track_order" \
  -H "Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{"minScore": 0.8}' | jq -c '{name, minScore, revision}'
```

##### CLI (Iris)

```bash
iris intent-router intents update track_order --min-score 0.8
```



The intent now matches only queries that score at least `0.8`. Higher scores are stricter.

## Clean up

Delete the intents when you finish. Deleting a missing intent succeeds. To remove every intent at once and keep the Router, [clear the Router](https://redis.io/docs/latest/develop/ai/context-engine/intent-router/manage-intents#clear-a-router).

**Available in:** Python (Iris), TypeScript (Iris), cURL (Iris), CLI (Iris)

##### Python (Iris)

```python
for name in ("track_order", "refund"):
    router.remove(name)
```

##### TypeScript (Iris)

```typescript
for (const name of ["track_order", "refund"]) {
  await router.deleteIntent(name);
}
```

##### cURL (Iris)

```bash
ROUTER_API="${IRIS_INTENT_ROUTER_URL%/}/iris/data/v1/intent/routers/$IRIS_INTENT_ROUTER_ID"
for name in track_order refund; do
  curl --fail-with-body --silent --show-error \
    -X DELETE "$ROUTER_API/intents/$name" \
    -H "Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY"
done
```

##### CLI (Iris)

```bash
for name in track_order refund; do
  iris intent-router intents delete "$name" --yes
done
```



## Next steps

- [Manage intents and examples](https://redis.io/docs/latest/develop/ai/context-engine/intent-router/manage-intents) to author intents in bulk and update them safely.
- [Match queries](https://redis.io/docs/latest/develop/ai/context-engine/intent-router/match) to tune thresholds and result limits.
- [Manage Routers](https://redis.io/docs/latest/develop/ai/context-engine/intent-router/manage-routers) to create Routers and choose an embedding model.

