{
  "schema_version": 2,
  "id": "operate/iris/context-gateway/self-managed/api-examples",
  "title": "Self-managed Context Gateway API examples",
  "url": "https://redis.io/docs/latest/operate/iris/context-gateway/self-managed/api-examples/",
  "summary": "Create the Gateways and the sample Upstream, mint an agent key, verify agent access, and rotate or revoke keys.",
  "tags": [
    "docs",
    "operate",
    "iris"
  ],
  "last_updated": "2026-11-02T17:11:02-08:00",
  "page_type": "content",
  "content_hash": "1d163b7b54e89974702a59ccc8ad7edadc833c9582ab461b3828ce972cb100ec",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "Create sample Gateways for full and search mode, register the clinic directory on both, and issue an agent key. The [quickstart](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/quickstart) uses one of these Gateways. The [MCP walkthrough](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/mcp#stored-result-example) uses the search-mode Gateway with compression enabled.\n\nBefore you begin, [deploy the chart](https://redis.io/docs/latest/operate/iris/context-gateway/self-managed/deploy) and [load the admin token](https://redis.io/docs/latest/operate/iris/context-gateway/self-managed/authentication#control-plane-admin-token)."
    },
    {
      "id": "set-connection-values",
      "title": "Set connection values",
      "role": "content",
      "text": "Forward the Control Plane and the Identity Service in separate terminals, as in [Deploy](https://redis.io/docs/latest/operate/iris/context-gateway/self-managed/deploy#5-verify-pods-and-health), then export the connection values:\n\n[code example]\n\n`IRIS_CONTEXT_GATEWAY_SERVICE_TOKEN` holds the admin token. For application deployment, use the Control Plane and Identity Service endpoints your platform exposes."
    },
    {
      "id": "create-the-gateways",
      "title": "Create the Gateways",
      "role": "content",
      "text": "These examples use Bash, cURL, jq, and `redis-cli`. Use a dedicated demo Surface database with JSON and Search support. Register it in both planes, separately from the Gateway database. Enable `compression.enabled` in the Data Plane and use a Gateway database with JSON and `maxmemory-policy noeviction`.\n\nChoose the registry IDs:\n\n[code example]\n\nCreate a `FULL` mode Gateway with compression disabled, and a `SEARCH` mode Gateway with compression enabled:\n\n[code example]\n\nThe `SEARCH` mode Gateway explicitly enables compression. Creation fails if its database cannot support it. Cache remains disabled in this walkthrough. Compression also needs `compression.enabled` on the Data Plane. See [Cache and compression](https://redis.io/docs/latest/operate/iris/context-gateway/self-managed/configuration#cache-and-compression)."
    },
    {
      "id": "register-the-sample-upstream",
      "title": "Register the sample Upstream",
      "role": "content",
      "text": "Save the complete JSON model from [Write a data model](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/manage-context-surfaces#write-a-data-model) as `clinic-model.json`. It defines `Location` and `Provider`, including the `specialty` and `location_id` TAG fields. Load these synthetic records into the dedicated demo database. The commands replace only these five sample keys:\n\n[code example]\n\nUse the TLS scheme `rediss://` when the database requires it. Keep the real connection URL out of source control. For a password, prefer `REDISCLI_AUTH` over placing the password in command arguments. Importers must normalize line breaks in TEXT fields to spaces before writing records.\n\nRegister this model on both Gateways. Sharing the Surface database is intentional here: both Gateways should expose the same demo records.\n\n[code example]\n\nIf `initialCatalogFailure` is present, stop and fix the reported database or configuration error before continuing. Indexing happens in the background. Wait for indexing to finish before comparing result counts. The expected dataset has three cardiologists: two at Clinic A and one at Clinic B."
    },
    {
      "id": "mint-an-agent-key",
      "title": "Mint an agent key",
      "role": "content",
      "text": "Issue one key with a `use` grant on each Gateway:\n\n[code example]\n\n> [!WARNING]\n> The response's `token` is the agent key, and it is returned only on creation or rotation. Save it in your secret manager and keep its `keyId`."
    },
    {
      "id": "verify-agent-access",
      "title": "Verify agent access",
      "role": "content",
      "text": "Use the returned endpoints rather than constructing MCP URLs. They must be reachable from the developer's machine:\n\n[code example]\n\nUse Python 3.11 or later. Run this program to authenticate and list both catalogs:\n\n[code example]\n\nThe full-mode catalog includes `scheduling__filter_provider`. The search-mode catalog includes `search_tools`, `run_tool`, and the handle tools, including `run_tool_as_handle` and `count_results`. Continue with the [quickstart](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/quickstart) to call the sample tools."
    },
    {
      "id": "rotate-or-revoke-agent-keys",
      "title": "Rotate or revoke agent keys",
      "role": "content",
      "text": "Rotate a key to issue a new token for the same grants. The grace period keeps the old token valid while applications switch:\n\n[code example]\n\nRevoke a key you no longer need:\n\n[code example]\n\nA revoked key stops working within the Identity Service cache lifetime, 300 seconds by default."
    },
    {
      "id": "hand-off-to-a-developer",
      "title": "Hand off to a developer",
      "role": "content",
      "text": "For the quickstart, give the developer the chosen Gateway’s `mcpEndpoint` as `IRIS_CONTEXT_GATEWAY_URL` and the agent key as `IRIS_CONTEXT_GATEWAY_API_KEY`. Use Operations for search mode or Front desk for full mode. For the MCP walkthrough, provide Operations as `IRIS_CONTEXT_GATEWAY_URL`. Give platform teams who register Upstreams the Control Plane URL and admin token for [Manage Gateways and Upstreams](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/manage-gateways). Remove the local key-response files after you save the token."
    },
    {
      "id": "use-the-cli-instead",
      "title": "Use the CLI instead",
      "role": "content",
      "text": "The `iris context-gateway` command-line interface (CLI) in the [redis-iris package](https://pypi.org/project/redis-iris/) also manages Gateways. Install the version pinned in the [quickstart](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/quickstart#install-the-client). With `IRIS_IDENTITY_URL` and `IRIS_IDENTITY_TOKEN` exported, create a Gateway, mint its agent key, and write the developer's environment file in one command:\n\n[code example]\n\n`--write-env` writes `IRIS_CONTEXT_GATEWAY_URL`, `IRIS_CONTEXT_GATEWAY_ID`, and `IRIS_CONTEXT_GATEWAY_API_KEY` to the file with mode `0600`, and the key is never printed. Add `--tool-exposure-mode search` and `--database-id <gateway-database-id>` for the operations Gateway. `service key` mints an agent key. `iris identity keys list --product context-gateway` lists keys, and `iris identity keys revoke <key-id>` revokes one. See [Manage Gateways and Upstreams](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/manage-gateways) for every operation."
    }
  ],
  "examples": [
    {
      "id": "set-connection-values-ex0",
      "language": "bash",
      "code": "export IRIS_CONTEXT_GATEWAY_SERVICE_URL='http://localhost:9100'\nexport IRIS_IDENTITY_URL='http://localhost:9200'\nexport IRIS_IDENTITY_TOKEN='<identity-service-control-token>'\nexport IRIS_IDENTITY_TENANT='<tenant-id>'\numask 077",
      "section_id": "set-connection-values"
    },
    {
      "id": "create-the-gateways-ex0",
      "language": "bash",
      "code": "export GATEWAY_DATABASE_ID='<gateway-database-id>'\nexport SURFACE_DATABASE_ID='<surface-database-id>'",
      "section_id": "create-the-gateways"
    },
    {
      "id": "create-the-gateways-ex1",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X POST \"$IRIS_CONTEXT_GATEWAY_SERVICE_URL/iris/v1/context-gateway/gateways\" \\\n  -H \"Authorization: Bearer $IRIS_CONTEXT_GATEWAY_SERVICE_TOKEN\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"name\": \"Front desk\", \"toolExposureMode\": \"FULL\", \"cache\": \"DISABLED\", \"compression\": \"DISABLED\"}' > front-desk.json\n\njq -n --arg database \"$GATEWAY_DATABASE_ID\" '{\n  name: \"Operations\", toolExposureMode: \"SEARCH\", databaseId: $database,\n  cache: \"DISABLED\", compression: \"ENABLED\"\n}' > operations-create.json\ncurl --fail-with-body --silent --show-error \\\n  -X POST \"$IRIS_CONTEXT_GATEWAY_SERVICE_URL/iris/v1/context-gateway/gateways\" \\\n  -H \"Authorization: Bearer $IRIS_CONTEXT_GATEWAY_SERVICE_TOKEN\" \\\n  -H 'Content-Type: application/json' \\\n  --data-binary @operations-create.json > operations.json\n\nexport FRONT_DESK_ID=\"$(jq -er '.gatewayId' front-desk.json)\"\nexport OPERATIONS_ID=\"$(jq -er '.gatewayId' operations.json)\"\njq '{gatewayId, mcpEndpoint, toolExposureMode, compression}' front-desk.json operations.json",
      "section_id": "create-the-gateways"
    },
    {
      "id": "register-the-sample-upstream-ex0",
      "language": "bash",
      "code": "export SURFACE_REDIS_URL='<surface-redis-url>'\nredis-cli -u \"$SURFACE_REDIS_URL\" JSON.SET location:clinic-a '$' \\\n  '{\"id\":\"clinic-a\",\"name\":\"Clinic A\",\"city\":\"Boston\"}'\nredis-cli -u \"$SURFACE_REDIS_URL\" JSON.SET location:clinic-b '$' \\\n  '{\"id\":\"clinic-b\",\"name\":\"Clinic B\",\"city\":\"Boston\"}'\nredis-cli -u \"$SURFACE_REDIS_URL\" JSON.SET provider:p1 '$' \\\n  '{\"id\":\"p1\",\"specialty\":\"cardiology\",\"location_id\":\"clinic-a\"}'\nredis-cli -u \"$SURFACE_REDIS_URL\" JSON.SET provider:p2 '$' \\\n  '{\"id\":\"p2\",\"specialty\":\"cardiology\",\"location_id\":\"clinic-a\"}'\nredis-cli -u \"$SURFACE_REDIS_URL\" JSON.SET provider:p3 '$' \\\n  '{\"id\":\"p3\",\"specialty\":\"cardiology\",\"location_id\":\"clinic-b\"}'",
      "section_id": "register-the-sample-upstream"
    },
    {
      "id": "register-the-sample-upstream-ex1",
      "language": "bash",
      "code": "jq -n --arg database \"$SURFACE_DATABASE_ID\" --slurpfile model clinic-model.json '{\n  name: \"Scheduling\", namespace: \"scheduling\", kind: \"CONTEXT_SURFACE\",\n  contextSurface: {databaseId: $database, dataModel: $model[0]}\n}' > surface-create.json\n\nfor gateway_id in \"$FRONT_DESK_ID\" \"$OPERATIONS_ID\"; do\n  curl --fail-with-body --silent --show-error \\\n    -X POST \"$IRIS_CONTEXT_GATEWAY_SERVICE_URL/iris/v1/context-gateway/gateways/$gateway_id/upstreams\" \\\n    -H \"Authorization: Bearer $IRIS_CONTEXT_GATEWAY_SERVICE_TOKEN\" \\\n    -H 'Content-Type: application/json' \\\n    --data-binary @surface-create.json > \"surface-$gateway_id.json\"\n  jq -e '(.initialCatalogFailure == null) and (.upstreamId != null)' \"surface-$gateway_id.json\"\ndone",
      "section_id": "register-the-sample-upstream"
    },
    {
      "id": "mint-an-agent-key-ex0",
      "language": "bash",
      "code": "jq -n --arg tenant \"$IRIS_IDENTITY_TENANT\" --arg a \"$FRONT_DESK_ID\" --arg b \"$OPERATIONS_ID\" '{\n  name: \"front-desk-agent\",\n  grants: [\n    {tenant: $tenant, product: \"context-gateway\", resourceType: \"gateway\", resourceId: $a, actions: [\"use\"]},\n    {tenant: $tenant, product: \"context-gateway\", resourceType: \"gateway\", resourceId: $b, actions: [\"use\"]}\n  ]\n}' > agent-grant.json\n\ncurl --fail-with-body --silent --show-error \\\n  -X POST \"$IRIS_IDENTITY_URL/v1/api-keys\" \\\n  -H \"Authorization: Bearer $IRIS_IDENTITY_TOKEN\" \\\n  -H 'Content-Type: application/json' \\\n  --data-binary @agent-grant.json > agent-key.json\nexport IRIS_CONTEXT_GATEWAY_API_KEY=\"$(jq -er '.token' agent-key.json)\"",
      "section_id": "mint-an-agent-key"
    },
    {
      "id": "verify-agent-access-ex0",
      "language": "bash",
      "code": "export IRIS_CONTEXT_GATEWAY_URL=\"$(jq -er '.mcpEndpoint' front-desk.json)\"\nexport SEARCH_GATEWAY_URL=\"$(jq -er '.mcpEndpoint' operations.json)\"\npython -m venv .venv\nsource .venv/bin/activate\npip install redis-iris",
      "section_id": "verify-agent-access"
    },
    {
      "id": "verify-agent-access-ex1",
      "language": "python",
      "code": "import os\n\nfrom redis_iris import ContextGateway\n\nfor setting in (\"IRIS_CONTEXT_GATEWAY_URL\", \"SEARCH_GATEWAY_URL\"):\n    gateway = ContextGateway.from_env({\n        \"IRIS_CONTEXT_GATEWAY_URL\": os.environ[setting],\n        \"IRIS_CONTEXT_GATEWAY_API_KEY\": os.environ[\"IRIS_CONTEXT_GATEWAY_API_KEY\"],\n    })\n    print(setting, [tool.name for tool in gateway.tools()])",
      "section_id": "verify-agent-access"
    },
    {
      "id": "rotate-or-revoke-agent-keys-ex0",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X POST \"$IRIS_IDENTITY_URL/v1/api-keys/<key-id>/rotate?graceSeconds=3600\" \\\n  -H \"Authorization: Bearer $IRIS_IDENTITY_TOKEN\"",
      "section_id": "rotate-or-revoke-agent-keys"
    },
    {
      "id": "rotate-or-revoke-agent-keys-ex1",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X DELETE \"$IRIS_IDENTITY_URL/v1/api-keys/<key-id>\" \\\n  -H \"Authorization: Bearer $IRIS_IDENTITY_TOKEN\"",
      "section_id": "rotate-or-revoke-agent-keys"
    },
    {
      "id": "use-the-cli-instead-ex0",
      "language": "bash",
      "code": "iris context-gateway service create --name front-desk --write-env .env",
      "section_id": "use-the-cli-instead"
    }
  ]
}
