{
  "schema_version": 2,
  "id": "develop/ai/context-engine/intent-router/quickstart",
  "title": "Redis Intent Router quickstart",
  "url": "https://redis.io/docs/latest/develop/ai/context-engine/intent-router/quickstart/",
  "summary": "Define two intents, match queries against them, and update an intent with Python, TypeScript, HTTP, or the Iris CLI.",
  "tags": [
    "docs",
    "develop",
    "ai"
  ],
  "last_updated": "2026-11-03T15:26:57-08:00",
  "page_type": "content",
  "content_hash": "77dbd5d685978c38d0f143ac7724760684a6434bfa570220f99e46c133d20071",
  "sections": [
    {
      "id": "code-examples",
      "title": "Code examples",
      "role": "example",
      "text": "These examples connect to Iris services using SDKs or HTTP requests with curl. Follow one language throughout each walkthrough.\n\n\nIntent 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."
    },
    {
      "id": "before-you-begin",
      "title": "Before you begin",
      "role": "content",
      "text": "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).\n\nThis walkthrough needs no agent framework or model-provider key.\n\nFollow 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).\n\n**Python and CLI**\n\n[code example]\n\n**TypeScript**\n\n[code example]\n\n**cURL**\n\n[code example]"
    },
    {
      "id": "save-connection-values",
      "title": "Save connection values",
      "role": "content",
      "text": "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.\n\n[code example]\n\nKeep keys out of source control and model prompts.\n\nThe 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."
    },
    {
      "id": "connect-to-the-router",
      "title": "Connect to the Router",
      "role": "content",
      "text": "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`.\n\n**Available in:** Python (Iris), TypeScript (Iris), cURL (Iris), CLI (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### TypeScript (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]\n\n##### CLI (Iris)\n\n[code example]\n\n\n\nThe 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."
    },
    {
      "id": "create-intents",
      "title": "Create intents",
      "role": "content",
      "text": "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.\n\n**Available in:** Python (Iris), TypeScript (Iris), cURL (Iris), CLI (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### TypeScript (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]\n\n##### CLI (Iris)\n\n[code example]\n\n\n\nEach 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`."
    },
    {
      "id": "match-a-query",
      "title": "Match a query",
      "role": "content",
      "text": "Send three queries. The response lists the closest intents, best first.\n\n**Available in:** Python (Iris), TypeScript (Iris), cURL (Iris), CLI (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### TypeScript (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]\n\n##### CLI (Iris)\n\n[code example]\n\n\n\nThe 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.\n\nScores vary with the Router's embedding model. If a query you expect to match returns nothing, add an example rather than lowering the threshold."
    },
    {
      "id": "add-an-example",
      "title": "Add an example",
      "role": "content",
      "text": "Add a phrasing to an existing intent.\n\n**Available in:** Python (Iris), TypeScript (Iris), cURL (Iris), CLI (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### TypeScript (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]\n\n##### CLI (Iris)\n\n[code example]\n\n\n\nThe next match uses the new example. Adding a phrasing that already exists is harmless."
    },
    {
      "id": "change-an-intents-threshold",
      "title": "Change an intent's threshold",
      "role": "content",
      "text": "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.\n\n**Available in:** Python (Iris), TypeScript (Iris), cURL (Iris), CLI (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### TypeScript (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]\n\n##### CLI (Iris)\n\n[code example]\n\n\n\nThe intent now matches only queries that score at least `0.8`. Higher scores are stricter."
    },
    {
      "id": "clean-up",
      "title": "Clean up",
      "role": "content",
      "text": "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).\n\n**Available in:** Python (Iris), TypeScript (Iris), cURL (Iris), CLI (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### TypeScript (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]\n\n##### CLI (Iris)\n\n[code example]"
    },
    {
      "id": "next-steps",
      "title": "Next steps",
      "role": "content",
      "text": "- [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.\n- [Match queries](https://redis.io/docs/latest/develop/ai/context-engine/intent-router/match) to tune thresholds and result limits.\n- [Manage Routers](https://redis.io/docs/latest/develop/ai/context-engine/intent-router/manage-routers) to create Routers and choose an embedding model."
    }
  ],
  "examples": [
    {
      "id": "before-you-begin-ex0",
      "language": "bash",
      "code": "python -m venv .venv\nsource .venv/bin/activate\npython -m pip install 'redis-iris>=1.0.0'",
      "section_id": "before-you-begin"
    },
    {
      "id": "before-you-begin-ex1",
      "language": "bash",
      "code": "npm install @redis-iris/intent-router",
      "section_id": "before-you-begin"
    },
    {
      "id": "before-you-begin-ex2",
      "language": "bash",
      "code": "curl --version\njq --version",
      "section_id": "before-you-begin"
    },
    {
      "id": "save-connection-values-ex0",
      "language": "bash",
      "code": "export IRIS_INTENT_ROUTER_URL='<data-plane-endpoint>'\nexport IRIS_INTENT_ROUTER_ID='<router-id>'\nexport IRIS_INTENT_ROUTER_API_KEY='<agent-key>'",
      "section_id": "save-connection-values"
    },
    {
      "id": "connect-to-the-router-ex0",
      "language": "python",
      "code": "from redis_iris.intent_router import IntentRouter, Target\n\nrouter = IntentRouter.from_env()\nprint(router.health())",
      "section_id": "connect-to-the-router"
    },
    {
      "id": "connect-to-the-router-ex1",
      "language": "typescript",
      "code": "import { IntentRouter } from \"@redis-iris/intent-router\";\n\nfunction requiredEnv(name: string): string {\n  const value = process.env[name];\n  if (!value) throw new Error(`Set ${name}`);\n  return value;\n}\n\nconst router = new IntentRouter({\n  serverURL: requiredEnv(\"IRIS_INTENT_ROUTER_URL\"),\n  routerId: requiredEnv(\"IRIS_INTENT_ROUTER_ID\"),\n  apiKey: requiredEnv(\"IRIS_INTENT_ROUTER_API_KEY\"),\n  retryConfig: { strategy: \"none\" },\n});\nconsole.log((await router.getRouterHealth()).result);",
      "section_id": "connect-to-the-router"
    },
    {
      "id": "connect-to-the-router-ex2",
      "language": "bash",
      "code": "set -euo pipefail\nROUTER_API=\"${IRIS_INTENT_ROUTER_URL%/}/iris/data/v1/intent/routers/$IRIS_INTENT_ROUTER_ID\"\ncurl --fail-with-body --silent --show-error \\\n  \"$ROUTER_API/health\" \\\n  -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\" | jq .",
      "section_id": "connect-to-the-router"
    },
    {
      "id": "connect-to-the-router-ex3",
      "language": "bash",
      "code": "set -euo pipefail\niris intent-router health",
      "section_id": "connect-to-the-router"
    },
    {
      "id": "create-intents-ex0",
      "language": "python",
      "code": "for intent in (\n    router.define(\n        \"track_order\",\n        description=\"The customer wants to know where an order is.\",\n        target=Target(\"tool\", \"orders.track\", {\"region\": \"eu\"}),\n        examples=[\"where is my order\", \"track my package\", \"has my parcel shipped\"],\n    ),\n    router.define(\n        \"refund\",\n        examples=[\"i want a refund\", \"refund my purchase\", \"i would like my money back\"],\n    ),\n):\n    print(intent.name, intent.example_count, intent.revision)",
      "section_id": "create-intents"
    },
    {
      "id": "create-intents-ex1",
      "language": "typescript",
      "code": "for (const intent of [\n  await router.upsertIntent(\"track_order\", undefined, undefined, {\n    description: \"The customer wants to know where an order is.\",\n    target: { type: \"tool\", ref: \"orders.track\", args: { region: \"eu\" } },\n    examples: [\"where is my order\", \"track my package\", \"has my parcel shipped\"],\n  }),\n  await router.upsertIntent(\"refund\", undefined, undefined, {\n    examples: [\"i want a refund\", \"refund my purchase\", \"i would like my money back\"],\n  }),\n]) {\n  console.log(intent.result.name, intent.result.exampleCount, intent.result.revision);\n}",
      "section_id": "create-intents"
    },
    {
      "id": "create-intents-ex2",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X PUT \"$ROUTER_API/intents/track_order\" \\\n  -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  --data '{\n    \"description\": \"The customer wants to know where an order is.\",\n    \"target\": {\"type\": \"tool\", \"ref\": \"orders.track\", \"args\": {\"region\": \"eu\"}},\n    \"examples\": [\"where is my order\", \"track my package\", \"has my parcel shipped\"]\n  }' | jq -c '{name, exampleCount, revision}'\ncurl --fail-with-body --silent --show-error \\\n  -X PUT \"$ROUTER_API/intents/refund\" \\\n  -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  --data '{\"examples\": [\"i want a refund\", \"refund my purchase\", \"i would like my money back\"]}' \\\n  | jq -c '{name, exampleCount, revision}'",
      "section_id": "create-intents"
    },
    {
      "id": "create-intents-ex3",
      "language": "bash",
      "code": "iris intent-router intents add track_order \\\n  --description \"The customer wants to know where an order is.\" \\\n  --target '{\"type\": \"tool\", \"ref\": \"orders.track\", \"args\": {\"region\": \"eu\"}}' \\\n  --example \"where is my order\" --example \"track my package\" --example \"has my parcel shipped\"\niris intent-router intents add refund \\\n  --example \"i want a refund\" --example \"refund my purchase\" --example \"i would like my money back\"",
      "section_id": "create-intents"
    },
    {
      "id": "match-a-query-ex0",
      "language": "python",
      "code": "for query in (\"where is my order please\", \"i would like my money back\", \"zzz qqq\"):\n    best = router.match(query).best\n    if best:\n        print(query, \"->\", best.name, round(best.score, 2), best.target)\n    else:\n        print(query, \"-> no match\")",
      "section_id": "match-a-query"
    },
    {
      "id": "match-a-query-ex1",
      "language": "typescript",
      "code": "for (const query of [\"where is my order please\", \"i would like my money back\", \"zzz qqq\"]) {\n  const { items } = (await router.match({ query })).result;\n  if (items.length > 0) {\n    console.log(query, \"->\", items[0].name, items[0].score.toFixed(2), items[0].target);\n  } else {\n    console.log(query, \"-> no match\");\n  }\n}",
      "section_id": "match-a-query"
    },
    {
      "id": "match-a-query-ex2",
      "language": "bash",
      "code": "for query in \"where is my order please\" \"i would like my money back\" \"zzz qqq\"; do\n  curl --fail-with-body --silent --show-error \\\n    -X POST \"$ROUTER_API/match\" \\\n    -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\" \\\n    -H 'Content-Type: application/json' \\\n    --data \"$(jq -n --arg query \"$query\" '{query: $query}')\" \\\n    | jq -r --arg query \"$query\" 'if (.items | length) > 0\n        then \"\\($query) -> \\(.items[0].name) \\(.items[0].score * 100 | round / 100) \\(.items[0].target | tojson)\"\n        else \"\\($query) -> no match\" end'\ndone",
      "section_id": "match-a-query"
    },
    {
      "id": "match-a-query-ex3",
      "language": "bash",
      "code": "for query in \"where is my order please\" \"i would like my money back\" \"zzz qqq\"; do\n  iris intent-router match \"$query\"\ndone",
      "section_id": "match-a-query"
    },
    {
      "id": "add-an-example-ex0",
      "language": "python",
      "code": "for example in router.add_examples(\"track_order\", [\"when will my delivery arrive\"]):\n    print(example.example_id, example.text)",
      "section_id": "add-an-example"
    },
    {
      "id": "add-an-example-ex1",
      "language": "typescript",
      "code": "const added = await router.addExamples(\"track_order\", {\n  examples: [\"when will my delivery arrive\"],\n});\nfor (const example of added.result.items) console.log(example.exampleId, example.text);",
      "section_id": "add-an-example"
    },
    {
      "id": "add-an-example-ex2",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X POST \"$ROUTER_API/intents/track_order/examples\" \\\n  -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  --data '{\"examples\": [\"when will my delivery arrive\"]}' | jq -c '.items[] | {exampleId, text}'",
      "section_id": "add-an-example"
    },
    {
      "id": "add-an-example-ex3",
      "language": "bash",
      "code": "iris intent-router examples add track_order \"when will my delivery arrive\"",
      "section_id": "add-an-example"
    },
    {
      "id": "change-an-intents-threshold-ex0",
      "language": "python",
      "code": "updated = router.update(\"track_order\", min_score=0.8)\nprint(updated.name, updated.min_score, updated.revision)",
      "section_id": "change-an-intents-threshold"
    },
    {
      "id": "change-an-intents-threshold-ex1",
      "language": "typescript",
      "code": "const { result: updated } = await router.updateIntent(\"track_order\", undefined, { minScore: 0.8 });\nconsole.log(updated.name, updated.minScore, updated.revision);",
      "section_id": "change-an-intents-threshold"
    },
    {
      "id": "change-an-intents-threshold-ex2",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X PATCH \"$ROUTER_API/intents/track_order\" \\\n  -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  --data '{\"minScore\": 0.8}' | jq -c '{name, minScore, revision}'",
      "section_id": "change-an-intents-threshold"
    },
    {
      "id": "change-an-intents-threshold-ex3",
      "language": "bash",
      "code": "iris intent-router intents update track_order --min-score 0.8",
      "section_id": "change-an-intents-threshold"
    },
    {
      "id": "clean-up-ex0",
      "language": "python",
      "code": "for name in (\"track_order\", \"refund\"):\n    router.remove(name)",
      "section_id": "clean-up"
    },
    {
      "id": "clean-up-ex1",
      "language": "typescript",
      "code": "for (const name of [\"track_order\", \"refund\"]) {\n  await router.deleteIntent(name);\n}",
      "section_id": "clean-up"
    },
    {
      "id": "clean-up-ex2",
      "language": "bash",
      "code": "ROUTER_API=\"${IRIS_INTENT_ROUTER_URL%/}/iris/data/v1/intent/routers/$IRIS_INTENT_ROUTER_ID\"\nfor name in track_order refund; do\n  curl --fail-with-body --silent --show-error \\\n    -X DELETE \"$ROUTER_API/intents/$name\" \\\n    -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\"\ndone",
      "section_id": "clean-up"
    },
    {
      "id": "clean-up-ex3",
      "language": "bash",
      "code": "for name in track_order refund; do\n  iris intent-router intents delete \"$name\" --yes\ndone",
      "section_id": "clean-up"
    }
  ]
}
