{
  "schema_version": 2,
  "id": "develop/ai/context-engine/intent-router/manage-intents",
  "title": "Manage intents and examples",
  "url": "https://redis.io/docs/latest/develop/ai/context-engine/intent-router/manage-intents/",
  "summary": "Create, update, replace, list, and delete intents and their example phrasings.",
  "tags": [
    "docs",
    "develop",
    "ai"
  ],
  "last_updated": "2026-10-30T10:17:15-04:00",
  "page_type": "content",
  "content_hash": "5fe522df4f7629340b9c44de88b2601c9678e3377c81f9fe7a25a1f2fce2ec7c",
  "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\nAn intent is a named group of example phrases that represent one thing a user might ask for, such as tracking an order or requesting a refund. The intents you write and their examples decide how well a Router classifies messages. This page shows how to create, read, update, and delete intents and their examples, how to avoid overwriting someone else's changes, and how to write examples that match well.\n\nThe examples use the connection values from the [quickstart](https://redis.io/docs/latest/develop/ai/context-engine/intent-router/quickstart#save-connection-values) and an agent key with `write` access. Follow one tab throughout the page."
    },
    {
      "id": "create-or-replace-an-intent",
      "title": "Create or replace an intent",
      "role": "content",
      "text": "Writing an intent with `PUT` creates it, or replaces the one with that name. It is idempotent: sending the same request twice produces the same intent, although each write returns a new `revision`. It returns `201` for a new intent and `200` for a replacement, and a replaced intent keeps its place in the list. In Python this is `define`, and in the CLI it is `intents add NAME`. Fields you leave out are cleared.\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\nAn intent takes up to 256 examples, each up to 2,048 characters. Phrasings already on the intent that your request omits are removed after the new ones are written, so a concurrent match never sees an empty intent."
    },
    {
      "id": "add-several-intents",
      "title": "Add several intents",
      "role": "content",
      "text": "Add up to 100 intents in one request. They are added in the order you send them, after the intents the Router already has. An intent whose name already exists is replaced in place, and every other intent is left alone. Nothing is written if any intent is invalid. In Python this is `define_many`. The CLI's `intents add --file` reads a JSON or YAML file that holds a list of intents, or a mapping with an `intents` list.\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": "read-and-list-intents",
      "title": "Read and list intents",
      "role": "content",
      "text": "Reading an intent returns its configuration, `exampleCount`, timestamps, and `revision`. It doesn't include the examples, which you list separately.\n\nListing returns intents with their configuration and example counts, in creation order. Pass `limit` (default 50, maximum 200). When more intents follow, the response includes `nextCursor`: pass it back as `cursor` for the next page. The Python `intents()` and `examples()` methods follow the cursor for you and return every item, and the CLI's `--all` does the same.\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": "update-an-intents-configuration",
      "title": "Update an intent's configuration",
      "role": "content",
      "text": "Update the description, target, `minScore`, or metadata as a merge patch, without touching or re-embedding the examples.\n\n- An omitted field stays unchanged.\n- `null` clears `description`, `target`, `minScore`, or `metadata`.\n- A `metadata` map replaces the whole existing map.\n- An empty body is rejected.\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\nClearing `minScore` makes the intent use the Router's threshold again. The CLI's `intents update` can't send `null`, so the CLI example changes only the target. To clear a field, use another client."
    },
    {
      "id": "avoid-overwriting-concurrent-changes",
      "title": "Avoid overwriting concurrent changes",
      "role": "content",
      "text": "Every intent has a `revision` that changes with each write to the intent. Read the intent, then send its revision as `expectedRevision` with your change, so the write succeeds only if nobody changed the intent in between. This example changes the description and leaves the rest of the intent alone. A conditional `PUT` works the same way but replaces the whole 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\nA stale revision fails with `412` and the type `/errors/revision-conflict`. Read the intent again, reapply your change, and retry. Because every write returns a new revision, a retry of a conditional write that already succeeded also fails with `412`: read the intent to check. Adding or deleting examples through the example operations doesn't change the revision."
    },
    {
      "id": "manage-examples",
      "title": "Manage examples",
      "role": "content",
      "text": "Add phrasings to an existing intent. Each request takes 1 to 256 examples and adds them after the existing ones. Repeating a phrasing keeps its place and doesn't embed it again.\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 response lists each example with its `exampleId`. List an intent's examples in the order they were written, with the same `limit` and `cursor` pagination as intents.\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\nRead or delete one example by its identifier. Reading an identifier from another intent returns `404`. Deleting an example the intent doesn't hold succeeds and changes nothing, and deleting under an intent that doesn't exist returns `404`.\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": "delete-an-intent",
      "title": "Delete an intent",
      "role": "content",
      "text": "Deleting an intent removes it and all its examples. Deleting a missing intent succeeds.\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": "clear-a-router",
      "title": "Clear a Router",
      "role": "content",
      "text": "Clearing removes every intent and example and keeps the Router. The `scope` is required, and `INTENTS` is the only value. There is no default, so a request can't empty a Router by accident. Clearing also removes the quickstart's intents, which the [Match queries](https://redis.io/docs/latest/develop/ai/context-engine/intent-router/match) examples create again before they run.\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": "write-good-examples",
      "title": "Write good examples",
      "role": "content",
      "text": "- **Vary the wording.** Include short and long phrasings, and the vocabulary your users really use.\n- **Keep each example about one thing.** An example that mixes two requests pulls the intent toward both.\n- **Separate overlapping intents.** If two intents keep matching the same queries, add examples that distinguish them, or raise their `minScore`.\n- **Add examples from real misses.** When a query returns the wrong intent or none, add it as an example of the right intent.\n\nSee [Match queries](https://redis.io/docs/latest/develop/ai/context-engine/intent-router/match) for how scores and thresholds interact with examples."
    }
  ],
  "examples": [
    {
      "id": "create-or-replace-an-intent-ex0",
      "language": "python",
      "code": "intent = router.define(\n    \"refund\",\n    description=\"The customer wants their money back.\",\n    target=Target(\"agent\", \"billing-agent\"),\n    min_score=0.75,\n    metadata={\"owner\": \"support\"},\n    examples=[\"i want a refund\", \"refund my purchase\"],\n)\nprint(intent.name, intent.example_count, intent.revision)",
      "section_id": "create-or-replace-an-intent"
    },
    {
      "id": "create-or-replace-an-intent-ex1",
      "language": "typescript",
      "code": "const { result: intent } = await router.upsertIntent(\"refund\", undefined, undefined, {\n  description: \"The customer wants their money back.\",\n  target: { type: \"agent\", ref: \"billing-agent\" },\n  minScore: 0.75,\n  metadata: { owner: \"support\" },\n  examples: [\"i want a refund\", \"refund my purchase\"],\n});\nconsole.log(intent.name, intent.exampleCount, intent.revision);",
      "section_id": "create-or-replace-an-intent"
    },
    {
      "id": "create-or-replace-an-intent-ex2",
      "language": "bash",
      "code": "ROUTER_API=\"${IRIS_INTENT_ROUTER_URL%/}/iris/data/v1/intent/routers/$IRIS_INTENT_ROUTER_ID\"\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 '{\n    \"description\": \"The customer wants their money back.\",\n    \"target\": {\"type\": \"agent\", \"ref\": \"billing-agent\"},\n    \"minScore\": 0.75,\n    \"metadata\": {\"owner\": \"support\"},\n    \"examples\": [\"i want a refund\", \"refund my purchase\"]\n  }' | jq -c '{name, exampleCount, revision}'",
      "section_id": "create-or-replace-an-intent"
    },
    {
      "id": "create-or-replace-an-intent-ex3",
      "language": "bash",
      "code": "iris intent-router intents add refund \\\n  --description \"The customer wants their money back.\" \\\n  --target '{\"type\": \"agent\", \"ref\": \"billing-agent\"}' \\\n  --min-score 0.75 --metadata owner=support \\\n  --example \"i want a refund\" --example \"refund my purchase\"",
      "section_id": "create-or-replace-an-intent"
    },
    {
      "id": "add-several-intents-ex0",
      "language": "python",
      "code": "added = router.define_many(\n    [\n        {\"name\": \"track_order\", \"examples\": [\"where is my order\", \"track my package\"]},\n        {\"name\": \"cancel_order\", \"examples\": [\"cancel my order\", \"i changed my mind\"]},\n    ]\n)\nfor item in added:\n    print(item.name, item.example_count)",
      "section_id": "add-several-intents"
    },
    {
      "id": "add-several-intents-ex1",
      "language": "typescript",
      "code": "const { result } = await router.addIntents({\n  intents: [\n    { name: \"track_order\", examples: [\"where is my order\", \"track my package\"] },\n    { name: \"cancel_order\", examples: [\"cancel my order\", \"i changed my mind\"] },\n  ],\n});\nfor (const item of result.items) console.log(item.name, item.exampleCount);",
      "section_id": "add-several-intents"
    },
    {
      "id": "add-several-intents-ex2",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X POST \"$ROUTER_API/intents\" \\\n  -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  --data '{\"intents\": [\n    {\"name\": \"track_order\", \"examples\": [\"where is my order\", \"track my package\"]},\n    {\"name\": \"cancel_order\", \"examples\": [\"cancel my order\", \"i changed my mind\"]}\n  ]}' | jq -c '.items[] | {name, exampleCount}'",
      "section_id": "add-several-intents"
    },
    {
      "id": "add-several-intents-ex3",
      "language": "bash",
      "code": "cat > intents.json <<'JSON'\n{\"intents\": [\n  {\"name\": \"track_order\", \"examples\": [\"where is my order\", \"track my package\"]},\n  {\"name\": \"cancel_order\", \"examples\": [\"cancel my order\", \"i changed my mind\"]}\n]}\nJSON\niris intent-router intents add --file intents.json",
      "section_id": "add-several-intents"
    },
    {
      "id": "read-and-list-intents-ex0",
      "language": "python",
      "code": "for item in router.intents():\n    print(item.name, item.example_count)",
      "section_id": "read-and-list-intents"
    },
    {
      "id": "read-and-list-intents-ex1",
      "language": "typescript",
      "code": "const { result: page } = await router.listIntents(50);\nfor (const item of page.items) console.log(item.name, item.exampleCount);\nconsole.log(\"next cursor:\", page.nextCursor);",
      "section_id": "read-and-list-intents"
    },
    {
      "id": "read-and-list-intents-ex2",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  \"$ROUTER_API/intents?limit=50\" \\\n  -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\" > intents.json\njq -c '.items[] | {name, exampleCount}' intents.json\njq -r '\"next cursor: \\(.nextCursor)\"' intents.json",
      "section_id": "read-and-list-intents"
    },
    {
      "id": "read-and-list-intents-ex3",
      "language": "bash",
      "code": "iris intent-router intents list --limit 50",
      "section_id": "read-and-list-intents"
    },
    {
      "id": "update-an-intents-configuration-ex0",
      "language": "python",
      "code": "patched = router.update(\n    \"refund\",\n    min_score=None,\n    target=Target(\"agent\", \"refunds-agent\"),\n)\nprint(patched.name, patched.target, patched.min_score, patched.revision)",
      "section_id": "update-an-intents-configuration"
    },
    {
      "id": "update-an-intents-configuration-ex1",
      "language": "typescript",
      "code": "const { result: patched } = await router.updateIntent(\"refund\", undefined, {\n  minScore: null,\n  target: { type: \"agent\", ref: \"refunds-agent\" },\n});\nconsole.log(patched.name, patched.target, patched.minScore, patched.revision);",
      "section_id": "update-an-intents-configuration"
    },
    {
      "id": "update-an-intents-configuration-ex2",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X PATCH \"$ROUTER_API/intents/refund\" \\\n  -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  --data '{\"minScore\": null, \"target\": {\"type\": \"agent\", \"ref\": \"refunds-agent\"}}' \\\n  | jq -c '{name, target, minScore, revision}'",
      "section_id": "update-an-intents-configuration"
    },
    {
      "id": "update-an-intents-configuration-ex3",
      "language": "bash",
      "code": "iris intent-router intents update refund \\\n  --target '{\"type\": \"agent\", \"ref\": \"refunds-agent\"}'",
      "section_id": "update-an-intents-configuration"
    },
    {
      "id": "avoid-overwriting-concurrent-changes-ex0",
      "language": "python",
      "code": "current = router.intent(\"refund\")\nchanged = router.update(\n    \"refund\",\n    description=\"The customer wants a refund or a chargeback reversed.\",\n    expected_revision=current.revision,\n)\nprint(changed.name, changed.revision)",
      "section_id": "avoid-overwriting-concurrent-changes"
    },
    {
      "id": "avoid-overwriting-concurrent-changes-ex1",
      "language": "typescript",
      "code": "const { result: current } = await router.getIntent(\"refund\");\nconst { result: changed } = await router.updateIntent(\"refund\", undefined, {\n  description: \"The customer wants a refund or a chargeback reversed.\",\n  expectedRevision: current.revision,\n});\nconsole.log(changed.name, changed.revision);",
      "section_id": "avoid-overwriting-concurrent-changes"
    },
    {
      "id": "avoid-overwriting-concurrent-changes-ex2",
      "language": "bash",
      "code": "REVISION=$(curl --fail-with-body --silent --show-error \\\n  \"$ROUTER_API/intents/refund\" \\\n  -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\" | jq -er .revision)\ncurl --fail-with-body --silent --show-error \\\n  -X PATCH \"$ROUTER_API/intents/refund\" \\\n  -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  --data \"$(jq -n --arg rev \"$REVISION\" '{\n    description: \"The customer wants a refund or a chargeback reversed.\",\n    expectedRevision: $rev\n  }')\" | jq -c '{name, revision}'",
      "section_id": "avoid-overwriting-concurrent-changes"
    },
    {
      "id": "avoid-overwriting-concurrent-changes-ex3",
      "language": "bash",
      "code": "REVISION=$(iris --json intent-router intents show refund | jq -er .revision)\niris intent-router intents update refund \\\n  --description \"The customer wants a refund or a chargeback reversed.\" \\\n  --expected-revision \"$REVISION\"",
      "section_id": "avoid-overwriting-concurrent-changes"
    },
    {
      "id": "manage-examples-ex0",
      "language": "python",
      "code": "for example in router.add_examples(\"refund\", [\"send my money back\", \"i was charged twice\"]):\n    print(example.example_id, example.text)",
      "section_id": "manage-examples"
    },
    {
      "id": "manage-examples-ex1",
      "language": "typescript",
      "code": "const { result: added } = await router.addExamples(\"refund\", {\n  examples: [\"send my money back\", \"i was charged twice\"],\n});\nfor (const example of added.items) console.log(example.exampleId, example.text);",
      "section_id": "manage-examples"
    },
    {
      "id": "manage-examples-ex2",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X POST \"$ROUTER_API/intents/refund/examples\" \\\n  -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  --data '{\"examples\": [\"send my money back\", \"i was charged twice\"]}' | jq -c '.items[] | {exampleId, text}'",
      "section_id": "manage-examples"
    },
    {
      "id": "manage-examples-ex3",
      "language": "bash",
      "code": "iris intent-router examples add refund \"send my money back\" \"i was charged twice\"",
      "section_id": "manage-examples"
    },
    {
      "id": "manage-examples-ex4",
      "language": "python",
      "code": "examples = router.examples(\"refund\")\nfor example in examples:\n    print(example.example_id, example.text)",
      "section_id": "manage-examples"
    },
    {
      "id": "manage-examples-ex5",
      "language": "typescript",
      "code": "const { result: examples } = await router.listExamples(\"refund\", 50);\nfor (const example of examples.items) console.log(example.exampleId, example.text);",
      "section_id": "manage-examples"
    },
    {
      "id": "manage-examples-ex6",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  \"$ROUTER_API/intents/refund/examples?limit=50\" \\\n  -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\" > examples.json\njq -c '.items[] | {exampleId, text}' examples.json",
      "section_id": "manage-examples"
    },
    {
      "id": "manage-examples-ex7",
      "language": "bash",
      "code": "iris --json intent-router examples list refund --limit 50 > examples.json\njq -c '.items[] | {exampleId, text}' examples.json",
      "section_id": "manage-examples"
    },
    {
      "id": "manage-examples-ex8",
      "language": "python",
      "code": "router.remove_example(\"refund\", examples[0].example_id)",
      "section_id": "manage-examples"
    },
    {
      "id": "manage-examples-ex9",
      "language": "typescript",
      "code": "await router.deleteExample(\"refund\", examples.items[0].exampleId);",
      "section_id": "manage-examples"
    },
    {
      "id": "manage-examples-ex10",
      "language": "bash",
      "code": "EXAMPLE_ID=$(jq -er '.items[0].exampleId' examples.json)\ncurl --fail-with-body --silent --show-error \\\n  -X DELETE \"$ROUTER_API/intents/refund/examples/$EXAMPLE_ID\" \\\n  -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\"",
      "section_id": "manage-examples"
    },
    {
      "id": "manage-examples-ex11",
      "language": "bash",
      "code": "EXAMPLE_ID=$(jq -er '.items[0].exampleId' examples.json)\niris intent-router examples delete refund \"$EXAMPLE_ID\" --yes",
      "section_id": "manage-examples"
    },
    {
      "id": "delete-an-intent-ex0",
      "language": "python",
      "code": "router.remove(\"cancel_order\")",
      "section_id": "delete-an-intent"
    },
    {
      "id": "delete-an-intent-ex1",
      "language": "typescript",
      "code": "await router.deleteIntent(\"cancel_order\");",
      "section_id": "delete-an-intent"
    },
    {
      "id": "delete-an-intent-ex2",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X DELETE \"$ROUTER_API/intents/cancel_order\" \\\n  -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\"",
      "section_id": "delete-an-intent"
    },
    {
      "id": "delete-an-intent-ex3",
      "language": "bash",
      "code": "iris intent-router intents delete cancel_order --yes",
      "section_id": "delete-an-intent"
    },
    {
      "id": "clear-a-router-ex0",
      "language": "python",
      "code": "router.clear()",
      "section_id": "clear-a-router"
    },
    {
      "id": "clear-a-router-ex1",
      "language": "typescript",
      "code": "await router.clear({ scope: \"INTENTS\" });",
      "section_id": "clear-a-router"
    },
    {
      "id": "clear-a-router-ex2",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X POST \"$ROUTER_API/clear\" \\\n  -H \"Authorization: Bearer $IRIS_INTENT_ROUTER_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  --data '{\"scope\": \"INTENTS\"}'",
      "section_id": "clear-a-router"
    },
    {
      "id": "clear-a-router-ex3",
      "language": "bash",
      "code": "iris intent-router clear --scope intents --yes",
      "section_id": "clear-a-router"
    }
  ]
}
