Guardrails
Package: agentrouter.guardrails.v1 Service: GuardrailsService
Endpoints
List guardrails
Changed in v0.7.0 (new features): A project now reads the organization's guardrails alongside its own, and every guardrail, pattern and provider reports the level it sits at. The organization's rules are enforced on the project, so they belong in what it reads; a project still cannot edit them, and a write aimed at one is refused.
What it does: Returns guardrails matching the specified filters.
Request fields:
| Field | Required | Description |
|---|---|---|
customer_id | no | Owning customer scope; defaults to caller's session customer when empty. |
project_id | no | Owning project scope; defaults to caller's session project when empty. |
page | no | Cursor-pagination inputs. |
search | no | Optional substring search on guardrail name. |
types | no | Filter to guardrails of these types. |
exclude_types | no | Exclude guardrails of these types. |
statuses | no | Filter to guardrails in these statuses. |
severities | no | Filter to guardrails with these severity levels. |
categories | no | Filter to guardrails in these categories. |
include_templates | no | When true, include platform template rows (is_template=true). |
scope | no | The level this request names (tetrateio/fraser#9666). Unspecified reads as GUARDRAIL_SCOPE_PROJECT, so a client written before #9666 behaves exactly as it did. GUARDRAIL_SCOPE_ORGANIZATION requires project_id to be empty. An HTTP/JSON caller uses the binding with no /projects/{project_id} segment, because the project path requires that segment, and names the scope explicitly on top of it: scope=GUARDRAIL_SCOPE_ORGANIZATION as a query parameter on a GET or DELETE, and as a body field on a POST or PATCH. The binding fills customer_id only, so a request on it that leaves scope unset is refused as a project request naming no project. |
Response fields:
| Field | Required | Description |
|---|---|---|
guardrails | no | Guardrails matching the request filters, one page's worth. |
page | no | Cursor-pagination outputs. |
total | no | Total count of matching guardrails across all pages. |
{"signatures":{"go":"c.Guardrails().ListGuardrails(ctx, \u0026guardrailsv1.ListGuardrailsRequest{...})","python":"client.guardrails.listguardrails(...)","typescript":"client.guardrails.listguardrails({...})","cli":"tare api guardrails list","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"examples":{"go":"// No Go SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","python":"# No Python SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","typescript":"// No TypeScript SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","cli":"tare api guardrails list","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"persona":"Admin","httpVerb":"GET","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/guardrails","slug":"list-guardrails"}
Get a guardrail
Changed in v0.7.0 (new features): A project now reads the organization's guardrails alongside its own, and every guardrail, pattern and provider reports the level it sits at. The organization's rules are enforced on the project, so they belong in what it reads; a project still cannot edit them, and a write aimed at one is refused.
What it does: Returns a single guardrail by id.
Request fields:
| Field | Required | Description |
|---|---|---|
customer_id | no | Owning customer scope; defaults to caller's session customer when empty. |
project_id | no | Owning project scope; defaults to caller's session project when empty. |
id | yes | Required: uuid of the guardrail to fetch. |
scope | no | The level this request names (tetrateio/fraser#9666). Unspecified reads as GUARDRAIL_SCOPE_PROJECT, so a client written before #9666 behaves exactly as it did. GUARDRAIL_SCOPE_ORGANIZATION requires project_id to be empty. An HTTP/JSON caller uses the binding with no /projects/{project_id} segment, because the project path requires that segment, and names the scope explicitly on top of it: scope=GUARDRAIL_SCOPE_ORGANIZATION as a query parameter on a GET or DELETE, and as a body field on a POST or PATCH. The binding fills customer_id only, so a request on it that leaves scope unset is refused as a project request naming no project. |
Response fields:
| Field | Required | Description |
|---|---|---|
guardrail | no | The requested guardrail. |
{"signatures":{"go":"c.Guardrails().GetGuardrail(ctx, \u0026guardrailsv1.GetGuardrailRequest{...})","python":"client.guardrails.getguardrail(...)","typescript":"client.guardrails.getguardrail({...})","cli":"tare api guardrails get \u003cid\u003e","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H...\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"examples":{"go":"// No Go SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","python":"# No Python SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","typescript":"// No TypeScript SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","cli":"tare api guardrails get \u003cid\u003e","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H...\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"persona":"Admin","httpVerb":"GET","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/guardrails/{id}","slug":"get-a-guardrail"}
Create a guardrail
Changed in v0.7.0 (behaviour changes): A project owner now creates, edits and deletes the guardrails and guardrail rules of a project they own, without an organization-wide guardrails credential. The shared pattern library and the external guardrail providers stay administrator-only, and a project owner still reaches no other project's guardrails.
Changed in v0.7.0 (new features): You can now author a guardrail, a guardrail rule, a guardrail provider and a pattern for a whole organization rather than one project at a time. Send scope GUARDRAIL_SCOPE_ORGANIZATION with no project_id, and every project of that customer is served the rule. A request that names a project behaves exactly as it did, and a request that names both is refused, so a caller that forgot the project cannot write into every project by accident.
What it does: Creates a new guardrail.
Request fields:
| Field | Required | Description |
|---|---|---|
customer_id | no | Owning customer scope; defaults to caller's session customer when empty. |
project_id | no | Owning project scope; defaults to caller's session project when empty. |
guardrail | yes | Required: guardrail to create. id must be absent or empty (server-assigned). |
scope | no | The level this request names (tetrateio/fraser#9666). Unspecified reads as GUARDRAIL_SCOPE_PROJECT, so a client written before #9666 behaves exactly as it did. GUARDRAIL_SCOPE_ORGANIZATION requires project_id to be empty. An HTTP/JSON caller uses the binding with no /projects/{project_id} segment, because the project path requires that segment, and names the scope explicitly on top of it: scope=GUARDRAIL_SCOPE_ORGANIZATION as a query parameter on a GET or DELETE, and as a body field on a POST or PATCH. The binding fills customer_id only, so a request on it that leaves scope unset is refused as a project request naming no project. |
Response fields:
| Field | Required | Description |
|---|---|---|
guardrail | no | The created guardrail with server-assigned fields populated. |
{"signatures":{"go":"c.Guardrails().CreateGuardrail(ctx, \u0026guardrailsv1.CreateGuardrailRequest{...})","python":"client.guardrails.createguardrail(...)","typescript":"client.guardrails.createguardrail({...})","cli":"tare api guardrails create --guardrail $GUARDRAIL","curl":"curl -X POST \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"guardrail\": {},\n \"scope\": \"...\"\n }'"},"examples":{"go":"// No Go SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","python":"# No Python SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","typescript":"// No TypeScript SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","cli":"tare api guardrails create --guardrail $GUARDRAIL","curl":"curl -X POST \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"guardrail\": {},\n \"scope\": \"...\"\n }'"},"persona":"Admin","httpVerb":"POST","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/guardrails","slug":"create-a-guardrail"}
Update a guardrail
Changed in v0.7.0 (behaviour changes): A project owner now creates, edits and deletes the guardrails and guardrail rules of a project they own, without an organization-wide guardrails credential. The shared pattern library and the external guardrail providers stay administrator-only, and a project owner still reaches no other project's guardrails.
Changed in v0.7.0 (new features): You can now author a guardrail, a guardrail rule, a guardrail provider and a pattern for a whole organization rather than one project at a time. Send scope GUARDRAIL_SCOPE_ORGANIZATION with no project_id, and every project of that customer is served the rule. A request that names a project behaves exactly as it did, and a request that names both is refused, so a caller that forgot the project cannot write into every project by accident.
What it does: Updates mutable guardrail fields. Omitted/empty scalar string fields leave the existing value untouched. Enum fields set to *_UNSPECIFIED leave the existing value untouched. Absent message fields (triggered_response) leave the existing value untouched; a present triggered_response replaces it wholesale. The guardrail id must be set inside the guardrail field. Returns PERMISSION_DENIED when the target guardrail is a template (is_template=true); templates are instantiated via CreateGuardrailFromTemplate, never mutated.
Request fields:
| Field | Required | Description |
|---|---|---|
customer_id | no | Owning customer scope; defaults to caller's session customer when empty. |
project_id | no | Owning project scope; defaults to caller's session project when empty. |
guardrail | yes | Required: guardrail to update. guardrail.id must be set. Partial update semantics: omitted/empty scalar string fields leave the existing value untouched; enum fields set to *_UNSPECIFIED leave the existing value untouched; absent message fields (triggered_response) leave the existing value untouched. |
scope | no | The level this request names (tetrateio/fraser#9666). Unspecified reads as GUARDRAIL_SCOPE_PROJECT, so a client written before #9666 behaves exactly as it did. GUARDRAIL_SCOPE_ORGANIZATION requires project_id to be empty. An HTTP/JSON caller uses the binding with no /projects/{project_id} segment, because the project path requires that segment, and names the scope explicitly on top of it: scope=GUARDRAIL_SCOPE_ORGANIZATION as a query parameter on a GET or DELETE, and as a body field on a POST or PATCH. The binding fills customer_id only, so a request on it that leaves scope unset is refused as a project request naming no project. |
Response fields:
| Field | Required | Description |
|---|---|---|
guardrail | no | The updated guardrail with server-assigned fields populated. |
{"signatures":{"go":"c.Guardrails().UpdateGuardrail(ctx, \u0026guardrailsv1.UpdateGuardrailRequest{...})","python":"client.guardrails.updateguardrail(...)","typescript":"client.guardrails.updateguardrail({...})","cli":"tare api guardrails update --guardrail $GUARDRAIL","curl":"curl -X PATCH \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H...\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"guardrail\": {},\n \"scope\": \"...\"\n }'"},"examples":{"go":"// No Go SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","python":"# No Python SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","typescript":"// No TypeScript SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","cli":"tare api guardrails update --guardrail $GUARDRAIL","curl":"curl -X PATCH \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H...\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"guardrail\": {},\n \"scope\": \"...\"\n }'"},"persona":"Admin","httpVerb":"PATCH","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/guardrails/{guardrail.id}","slug":"update-a-guardrail"}
Delete a guardrail
Changed in v0.7.0 (behaviour changes): A project owner now creates, edits and deletes the guardrails and guardrail rules of a project they own, without an organization-wide guardrails credential. The shared pattern library and the external guardrail providers stay administrator-only, and a project owner still reaches no other project's guardrails.
What it does: Soft-deletes a guardrail (sets deleted_at; the row disappears from List/Get). Child rules of the soft-deleted guardrail are no longer served. Historical trigger records referencing this guardrail REMAIN queryable. Returns PERMISSION_DENIED when the target guardrail is a template (is_template=true); templates are instantiated via CreateGuardrailFromTemplate, never mutated.
Request fields:
| Field | Required | Description |
|---|---|---|
customer_id | no | Owning customer scope; defaults to caller's session customer when empty. |
project_id | no | Owning project scope; defaults to caller's session project when empty. |
id | yes | Required: uuid of the guardrail to delete. |
scope | no | The level this request names (tetrateio/fraser#9666). Unspecified reads as GUARDRAIL_SCOPE_PROJECT, so a client written before #9666 behaves exactly as it did. GUARDRAIL_SCOPE_ORGANIZATION requires project_id to be empty. An HTTP/JSON caller uses the binding with no /projects/{project_id} segment, because the project path requires that segment, and names the scope explicitly on top of it: scope=GUARDRAIL_SCOPE_ORGANIZATION as a query parameter on a GET or DELETE, and as a body field on a POST or PATCH. The binding fills customer_id only, so a request on it that leaves scope unset is refused as a project request naming no project. |
{"signatures":{"go":"c.Guardrails().DeleteGuardrail(ctx, \u0026guardrailsv1.DeleteGuardrailRequest{...})","python":"client.guardrails.deleteguardrail(...)","typescript":"client.guardrails.deleteguardrail({...})","cli":"tare api guardrails delete \u003cid\u003e","curl":"curl -X DELETE \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H...\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"examples":{"go":"// No Go SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","python":"# No Python SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","typescript":"// No TypeScript SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","cli":"tare api guardrails delete \u003cid\u003e","curl":"curl -X DELETE \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H...\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"persona":"Admin","httpVerb":"DELETE","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/guardrails/{id}","slug":"delete-a-guardrail"}
Set guardrail status
Changed in v0.7.0 (behaviour changes): A project owner now creates, edits and deletes the guardrails and guardrail rules of a project they own, without an organization-wide guardrails credential. The shared pattern library and the external guardrail providers stay administrator-only, and a project owner still reaches no other project's guardrails.
What it does: Updates the status and/or enabled flag of a guardrail. At least one of status/enabled must be provided; otherwise INVALID_ARGUMENT. Returns PERMISSION_DENIED when the target guardrail is a template (is_template=true); templates are instantiated via CreateGuardrailFromTemplate, never mutated.
Request fields:
| Field | Required | Description |
|---|---|---|
customer_id | no | Owning customer scope; defaults to caller's session customer when empty. |
project_id | no | Owning project scope; defaults to caller's session project when empty. |
id | yes | Required: uuid of the guardrail to update. |
status | no | New operational status for the guardrail. GUARDRAIL_STATUS_UNSPECIFIED leaves the stored status unchanged. |
enabled | no | New enabled state. When absent the enabled field is left unchanged. |
scope | no | The level this request names (tetrateio/fraser#9666). Unspecified reads as GUARDRAIL_SCOPE_PROJECT, so a client written before #9666 behaves exactly as it did. GUARDRAIL_SCOPE_ORGANIZATION requires project_id to be empty. An HTTP/JSON caller uses the binding with no /projects/{project_id} segment, because the project path requires that segment, and names the scope explicitly on top of it: scope=GUARDRAIL_SCOPE_ORGANIZATION as a query parameter on a GET or DELETE, and as a body field on a POST or PATCH. The binding fills customer_id only, so a request on it that leaves scope unset is refused as a project request naming no project. |
Response fields:
| Field | Required | Description |
|---|---|---|
guardrail | no | The guardrail with the updated status. |
{"signatures":{"go":"c.Guardrails().SetGuardrailStatus(ctx, \u0026guardrailsv1.SetGuardrailStatusRequest{...})","python":"client.guardrails.setguardrailstatus(...)","typescript":"client.guardrails.setguardrailstatus({...})","cli":"tare api guardrails set-status --id $ID","curl":"curl -X POST \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H.../status\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"status\": \"...\",\n \"enabled\": false,\n \"scope\": \"...\"\n }'"},"examples":{"go":"// No Go SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","python":"# No Python SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","typescript":"// No TypeScript SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","cli":"tare api guardrails set-status --id $ID","curl":"curl -X POST \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H.../status\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"status\": \"...\",\n \"enabled\": false,\n \"scope\": \"...\"\n }'"},"persona":"Admin","httpVerb":"POST","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/guardrails/{id}/status","slug":"set-guardrail-status"}
Create a guardrail from a template
Changed in v0.7.0 (behaviour changes): A project owner now creates, edits and deletes the guardrails and guardrail rules of a project they own, without an organization-wide guardrails credential. The shared pattern library and the external guardrail providers stay administrator-only, and a project owner still reaches no other project's guardrails.
What it does: Instantiates a new guardrail from a platform template row (is_template=true). The resulting guardrail is editable and scoped to (customer_id, project_id). Returns NOT_FOUND when template_id does not reference an existing template guardrail (non-template ids are treated as not found).
Request fields:
| Field | Required | Description |
|---|---|---|
customer_id | no | Owning customer scope; defaults to caller's session customer when empty. |
project_id | no | Owning project scope; defaults to caller's session project when empty. |
template_id | yes | Required: id of the template guardrail (is_template=true) to clone. |
name | yes | Required: display name for the new guardrail. |
description | no | Optional description for the new guardrail. |
scope | no | The level this request names (tetrateio/fraser#9666). Unspecified reads as GUARDRAIL_SCOPE_PROJECT, so a client written before #9666 behaves exactly as it did. GUARDRAIL_SCOPE_ORGANIZATION requires project_id to be empty. An HTTP/JSON caller uses the binding with no /projects/{project_id} segment, because the project path requires that segment, and names the scope explicitly on top of it: scope=GUARDRAIL_SCOPE_ORGANIZATION as a query parameter on a GET or DELETE, and as a body field on a POST or PATCH. The binding fills customer_id only, so a request on it that leaves scope unset is refused as a project request naming no project. |
Response fields:
| Field | Required | Description |
|---|---|---|
guardrail | no | The newly created guardrail instantiated from the template. |
{"signatures":{"go":"c.Guardrails().CreateGuardrailFromTemplate(ctx, \u0026guardrailsv1.CreateGuardrailFromTemplateRequest{...})","python":"client.guardrails.createguardrailfromtemplate(...)","typescript":"client.guardrails.createguardrailfromtemplate({...})","cli":"tare api guardrails create-from-template --template-id $TEMPLATE_ID --name $NAME","curl":"curl -X POST \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/from-template\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"template_id\": \"...\",\n \"name\": \"...\",\n \"description\": \"...\",\n \"scope\": \"...\"\n }'"},"examples":{"go":"// No Go SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","python":"# No Python SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","typescript":"// No TypeScript SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","cli":"tare api guardrails create-from-template --template-id $TEMPLATE_ID --name $NAME","curl":"curl -X POST \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/from-template\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"template_id\": \"...\",\n \"name\": \"...\",\n \"description\": \"...\",\n \"scope\": \"...\"\n }'"},"persona":"Admin","httpVerb":"POST","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/guardrails/from-template","slug":"create-a-guardrail-from-a-template"}
Get guardrail statistics
What it does: Returns aggregate statistics for guardrails in scope.
Request fields:
| Field | Required | Description |
|---|---|---|
customer_id | no | Owning customer scope; defaults to caller's session customer when empty. |
project_id | no | Owning project scope; defaults to caller's session project when empty. |
scope | no | The level this request names (tetrateio/fraser#9666). Unspecified reads as GUARDRAIL_SCOPE_PROJECT, so a client written before #9666 behaves exactly as it did. GUARDRAIL_SCOPE_ORGANIZATION requires project_id to be empty. An HTTP/JSON caller uses the binding with no /projects/{project_id} segment, because the project path requires that segment, and names the scope explicitly on top of it: scope=GUARDRAIL_SCOPE_ORGANIZATION as a query parameter on a GET or DELETE, and as a body field on a POST or PATCH. The binding fills customer_id only, so a request on it that leaves scope unset is refused as a project request naming no project. |
Response fields:
| Field | Required | Description |
|---|---|---|
total | no | Total number of guardrails in scope. |
active | no | Number of guardrails with status ACTIVE. |
by_type | no | Count of guardrails per GuardrailType. Keys are the stored lowercase domain values (e.g. security, compliance), not enum value names. |
by_severity | no | Count of guardrails per GuardrailSeverity. Keys are the stored lowercase domain values (e.g. critical, high), not enum value names. |
by_category | no | Count of guardrails per GuardrailCategory. Keys are the stored lowercase domain values (e.g. data-privacy, financial), not enum value names. |
{"signatures":{"go":"c.Guardrails().GetGuardrailStats(ctx, \u0026guardrailsv1.GetGuardrailStatsRequest{...})","python":"client.guardrails.getguardrailstats(...)","typescript":"client.guardrails.getguardrailstats({...})","cli":"tare api guardrails stats","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/stats\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"examples":{"go":"// No Go SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","python":"# No Python SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","typescript":"// No TypeScript SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","cli":"tare api guardrails stats","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/stats\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"persona":"Admin","httpVerb":"GET","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/guardrails/stats","slug":"get-guardrail-statistics"}
List guardrail rules
Changed in v0.7.0 (new features): Every guardrail rule now carries a reference, a short read-only id such as GR-0142 that the database mints once and never rewrites. The guardrail rule APIs and each trigger evaluation return it beside the display_name, and the data plane receives it in its runtime configuration, so a platform operator reading a trigger has one id to quote. Existing rules were numbered in creation order, and a blocked caller's refusal body does not carry the reference yet.
What it does: Returns rules for the specified guardrail.
Request fields:
| Field | Required | Description |
|---|---|---|
customer_id | no | Owning customer scope; defaults to caller's session customer when empty. |
project_id | no | Owning project scope; defaults to caller's session project when empty. |
page | no | Cursor-pagination inputs. |
guardrail_id | yes | Required: parent guardrail id. |
search | no | Optional substring search on rule name. |
active | no | When set, filter to active or inactive rules only. |
execute_on | no | Filter to rules with these execute_on values. |
provider_ids | no | Filter to rules referencing these provider ids. |
check_types | no | Filter to rules with these check_type values. |
actions | no | Filter to rules with these action values. |
modes | no | Filter to rules with these mode values. |
scope | no | The level this request names (tetrateio/fraser#9666). Unspecified reads as GUARDRAIL_SCOPE_PROJECT, so a client written before #9666 behaves exactly as it did. GUARDRAIL_SCOPE_ORGANIZATION requires project_id to be empty. An HTTP/JSON caller uses the binding with no /projects/{project_id} segment, because the project path requires that segment, and names the scope explicitly on top of it: scope=GUARDRAIL_SCOPE_ORGANIZATION as a query parameter on a GET or DELETE, and as a body field on a POST or PATCH. The binding fills customer_id only, so a request on it that leaves scope unset is refused as a project request naming no project. |
Response fields:
| Field | Required | Description |
|---|---|---|
rules | no | Rules matching the request filters, one page's worth. |
page | no | Cursor-pagination outputs. |
total | no | Total count of matching rules across all pages. |
{"signatures":{"go":"c.Guardrails().ListGuardrailRules(ctx, \u0026guardrailsv1.ListGuardrailRulesRequest{...})","python":"client.guardrails.listguardrailrules(...)","typescript":"client.guardrails.listguardrailrules({...})","cli":"tare api guardrails rules list --guardrail-id $GUARDRAIL_ID","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H.../rules\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"examples":{"go":"// No Go SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","python":"# No Python SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","typescript":"// No TypeScript SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","cli":"tare api guardrails rules list --guardrail-id $GUARDRAIL_ID","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H.../rules\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"persona":"Admin","httpVerb":"GET","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/guardrails/{guardrail_id}/rules","slug":"list-guardrail-rules"}
Get a guardrail rule
Changed in v0.7.0 (new features): Every guardrail rule now carries a reference, a short read-only id such as GR-0142 that the database mints once and never rewrites. The guardrail rule APIs and each trigger evaluation return it beside the display_name, and the data plane receives it in its runtime configuration, so a platform operator reading a trigger has one id to quote. Existing rules were numbered in creation order, and a blocked caller's refusal body does not carry the reference yet.
What it does: Returns a single rule by id. Returns NOT_FOUND when the rule does not exist under the given guardrail_id.
Request fields:
| Field | Required | Description |
|---|---|---|
customer_id | no | Owning customer scope; defaults to caller's session customer when empty. |
project_id | no | Owning project scope; defaults to caller's session project when empty. |
guardrail_id | yes | Required: parent guardrail id. |
id | yes | Required: uuid of the rule to fetch. |
scope | no | The level this request names (tetrateio/fraser#9666). Unspecified reads as GUARDRAIL_SCOPE_PROJECT, so a client written before #9666 behaves exactly as it did. GUARDRAIL_SCOPE_ORGANIZATION requires project_id to be empty. An HTTP/JSON caller uses the binding with no /projects/{project_id} segment, because the project path requires that segment, and names the scope explicitly on top of it: scope=GUARDRAIL_SCOPE_ORGANIZATION as a query parameter on a GET or DELETE, and as a body field on a POST or PATCH. The binding fills customer_id only, so a request on it that leaves scope unset is refused as a project request naming no project. |
Response fields:
| Field | Required | Description |
|---|---|---|
rule | no | The requested guardrail rule. |
{"signatures":{"go":"c.Guardrails().GetGuardrailRule(ctx, \u0026guardrailsv1.GetGuardrailRuleRequest{...})","python":"client.guardrails.getguardrailrule(...)","typescript":"client.guardrails.getguardrailrule({...})","cli":"tare api guardrails rules get --guardrail-id $GUARDRAIL_ID \u003cid\u003e","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H.../rules/01H...\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"examples":{"go":"// No Go SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","python":"# No Python SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","typescript":"// No TypeScript SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","cli":"tare api guardrails rules get --guardrail-id $GUARDRAIL_ID \u003cid\u003e","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H.../rules/01H...\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"persona":"Admin","httpVerb":"GET","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/guardrails/{guardrail_id}/rules/{id}","slug":"get-a-guardrail-rule"}
Create a guardrail rule
Changed in v0.11.0 (new features): Guardrail providers can be Amazon Bedrock Guardrails (kind bedrockguardrails): set region, optional endpoint and timeout, store a static AWS key pair with aws_credentials, and bind each rule to a guardrail ID and version. A rule bound to DRAFT returns a warning. Rule writes are refused while a data plane serving the rule's project, or for an organization-scope rule any data plane in the organization, runs a build older than 0.11.0 or has not reported a readable build.
Changed in v0.7.0 (behaviour changes): A project owner now creates, edits and deletes the guardrails and guardrail rules of a project they own, without an organization-wide guardrails credential. The shared pattern library and the external guardrail providers stay administrator-only, and a project owner still reaches no other project's guardrails.
Changed in v0.7.0 (new features): You can now author a guardrail, a guardrail rule, a guardrail provider and a pattern for a whole organization rather than one project at a time. Send scope GUARDRAIL_SCOPE_ORGANIZATION with no project_id, and every project of that customer is served the rule. A request that names a project behaves exactly as it did, and a request that names both is refused, so a caller that forgot the project cannot write into every project by accident.
Changed in v0.7.0 (new features): Every guardrail rule now carries a reference, a short read-only id such as GR-0142 that the database mints once and never rewrites. The guardrail rule APIs and each trigger evaluation return it beside the display_name, and the data plane receives it in its runtime configuration, so a platform operator reading a trigger has one id to quote. Existing rules were numbered in creation order, and a blocked caller's refusal body does not carry the reference yet.
Changed in v0.5.0 (behaviour changes): Creating or updating an externalservice guardrail provider now rejects, with INVALID_ARGUMENT, a config the data plane could not use: an unknown key or non-string value, a service_url that is not an absolute http or https URL or names a link-local or metadata address, a blank endpoint or one without a leading slash, a blank timeout or one outside 0-30s, or a ca_cert_pem over 8 KiB, over four certificates or holding anything else. Its rules need a raw.threshold above 0 and at most 1.
Changed in v0.5.0 (behaviour changes): Creating or updating a guardrail rule with the externalService configuration variant now fails with INVALID_ARGUMENT for every provider kind. A stored rule that still carries the variant stays readable and editable as long as the write does not send it back.
Changed in v0.5.0 (deprecations): The externalService variant of a guardrail rule's configuration is deprecated: nothing reads it, and its headers were never sent as HTTP headers. Connection settings and the credential live on the provider; per-check parameters go in the rule's raw configuration, where threshold is the one reserved key.
Changed in v0.4.0 (behaviour changes): Editing a guardrail rule that is bound to a provider outside its own project is now refused. The rule keeps enforcing and reading it is unaffected, but any update that touches its provider, check type or configuration fails until the rule is repointed at a provider its own project owns -- which can be done in the same update call. Only rules the guardrail-provider ownership migration reports as still bound outside their project are affected; it names the count in a notice reading "N non-template rule(s) remain bound outside their own project".
Changed in v0.4.0 (security updates): A guardrail rule can now be bound only to a provider its own project owns. A caller who knew another project's provider id could previously point a rule at it and send that project's traffic through another project's provider and credential, because the binding check asked only whether the provider existed and was usable, never who owned it. The refusal reads the same whether the id names another project's provider, a catalog template or nothing at all, so it cannot be used to discover which provider ids exist. Rules that already reference a provider in their own project are unaffected. No CVE; requires a caller authorized to write guardrails in some project. Rules written before this release are NOT rewritten, and any that the upgrade left bound outside their own project keep enforcing -- and keep exporting the other project's provider configuration, its endpoint and credential reference included, into the referencing project's data-plane configuration. The upgrade reports how many such rules remain: the guardrail-provider ownership migration raises a notice reading "N non-template rule(s) remain bound outside their own project". Repoint each of them at a provider its own project owns; until you do, the next edit to the rule's provider, check type or configuration is refused.
What it does: Adds a new rule to a guardrail. Returns PERMISSION_DENIED when the target guardrail is a template (is_template=true); templates are instantiated via CreateGuardrailFromTemplate, never mutated. A rule on a bedrockguardrails provider is refused with FAILED_PRECONDITION while a data plane serving the rule's scope reports a build older than 0.11.0, a build that cannot be read, or no build. The response's warnings carry non-fatal advisories, such as a binding to a guardrail's DRAFT.
Request fields:
| Field | Required | Description |
|---|---|---|
customer_id | no | Owning customer scope; defaults to caller's session customer when empty. |
project_id | no | Owning project scope; defaults to caller's session project when empty. |
guardrail_id | yes | Required: parent guardrail id (must match rule.guardrail_id when both are set). |
rule | yes | Required: rule to create. id must be absent or empty (server-assigned). |
scope | no | The level this request names (tetrateio/fraser#9666). Unspecified reads as GUARDRAIL_SCOPE_PROJECT, so a client written before #9666 behaves exactly as it did. GUARDRAIL_SCOPE_ORGANIZATION requires project_id to be empty. An HTTP/JSON caller uses the binding with no /projects/{project_id} segment, because the project path requires that segment, and names the scope explicitly on top of it: scope=GUARDRAIL_SCOPE_ORGANIZATION as a query parameter on a GET or DELETE, and as a body field on a POST or PATCH. The binding fills customer_id only, so a request on it that leaves scope unset is refused as a project request naming no project. |
Response fields:
| Field | Required | Description |
|---|---|---|
rule | no | The created rule with server-assigned fields populated. |
warnings | no | Non-fatal advisories about the rule as stored, such as a Bedrock guardrail bound to its DRAFT version. Empty when there is nothing to report. |
{"signatures":{"go":"c.Guardrails().CreateGuardrailRule(ctx, \u0026guardrailsv1.CreateGuardrailRuleRequest{...})","python":"client.guardrails.createguardrailrule(...)","typescript":"client.guardrails.createguardrailrule({...})","cli":"tare api guardrails rules create --guardrail-id $GUARDRAIL_ID --rule $RULE","curl":"curl -X POST \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H.../rules\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"rule\": {},\n \"scope\": \"...\"\n }'"},"examples":{"go":"// No Go SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","python":"# No Python SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","typescript":"// No TypeScript SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","cli":"tare api guardrails rules create --guardrail-id $GUARDRAIL_ID --rule $RULE","curl":"curl -X POST \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H.../rules\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"rule\": {},\n \"scope\": \"...\"\n }'"},"persona":"Admin","httpVerb":"POST","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/guardrails/{guardrail_id}/rules","slug":"create-a-guardrail-rule"}
Update a guardrail rule
Changed in v0.11.0 (new features): Guardrail providers can be Amazon Bedrock Guardrails (kind bedrockguardrails): set region, optional endpoint and timeout, store a static AWS key pair with aws_credentials, and bind each rule to a guardrail ID and version. A rule bound to DRAFT returns a warning. Rule writes are refused while a data plane serving the rule's project, or for an organization-scope rule any data plane in the organization, runs a build older than 0.11.0 or has not reported a readable build.
Changed in v0.7.0 (behaviour changes): A project owner now creates, edits and deletes the guardrails and guardrail rules of a project they own, without an organization-wide guardrails credential. The shared pattern library and the external guardrail providers stay administrator-only, and a project owner still reaches no other project's guardrails.
Changed in v0.7.0 (new features): You can now author a guardrail, a guardrail rule, a guardrail provider and a pattern for a whole organization rather than one project at a time. Send scope GUARDRAIL_SCOPE_ORGANIZATION with no project_id, and every project of that customer is served the rule. A request that names a project behaves exactly as it did, and a request that names both is refused, so a caller that forgot the project cannot write into every project by accident.
Changed in v0.7.0 (new features): Every guardrail rule now carries a reference, a short read-only id such as GR-0142 that the database mints once and never rewrites. The guardrail rule APIs and each trigger evaluation return it beside the display_name, and the data plane receives it in its runtime configuration, so a platform operator reading a trigger has one id to quote. Existing rules were numbered in creation order, and a blocked caller's refusal body does not carry the reference yet.
Changed in v0.5.0 (behaviour changes): Creating or updating an externalservice guardrail provider now rejects, with INVALID_ARGUMENT, a config the data plane could not use: an unknown key or non-string value, a service_url that is not an absolute http or https URL or names a link-local or metadata address, a blank endpoint or one without a leading slash, a blank timeout or one outside 0-30s, or a ca_cert_pem over 8 KiB, over four certificates or holding anything else. Its rules need a raw.threshold above 0 and at most 1.
Changed in v0.5.0 (behaviour changes): Creating or updating a guardrail rule with the externalService configuration variant now fails with INVALID_ARGUMENT for every provider kind. A stored rule that still carries the variant stays readable and editable as long as the write does not send it back.
Changed in v0.5.0 (deprecations): The externalService variant of a guardrail rule's configuration is deprecated: nothing reads it, and its headers were never sent as HTTP headers. Connection settings and the credential live on the provider; per-check parameters go in the rule's raw configuration, where threshold is the one reserved key.
Changed in v0.4.0 (behaviour changes): Editing a guardrail rule that is bound to a provider outside its own project is now refused. The rule keeps enforcing and reading it is unaffected, but any update that touches its provider, check type or configuration fails until the rule is repointed at a provider its own project owns -- which can be done in the same update call. Only rules the guardrail-provider ownership migration reports as still bound outside their project are affected; it names the count in a notice reading "N non-template rule(s) remain bound outside their own project".
Changed in v0.4.0 (security updates): A guardrail rule can now be bound only to a provider its own project owns. A caller who knew another project's provider id could previously point a rule at it and send that project's traffic through another project's provider and credential, because the binding check asked only whether the provider existed and was usable, never who owned it. The refusal reads the same whether the id names another project's provider, a catalog template or nothing at all, so it cannot be used to discover which provider ids exist. Rules that already reference a provider in their own project are unaffected. No CVE; requires a caller authorized to write guardrails in some project. Rules written before this release are NOT rewritten, and any that the upgrade left bound outside their own project keep enforcing -- and keep exporting the other project's provider configuration, its endpoint and credential reference included, into the referencing project's data-plane configuration. The upgrade reports how many such rules remain: the guardrail-provider ownership migration raises a notice reading "N non-template rule(s) remain bound outside their own project". Repoint each of them at a provider its own project owns; until you do, the next edit to the rule's provider, check type or configuration is refused.
What it does: Updates mutable rule fields. Omitted/empty scalar string fields leave the existing value untouched. Enum fields set to *_UNSPECIFIED leave the existing value untouched. Absent message fields (triggered_response, configuration) leave the existing value untouched; a present configuration Struct REPLACES the stored configuration wholesale (no deep merge). The rule id must be set inside the rule field. Returns PERMISSION_DENIED when the target rule's parent guardrail is a template (is_template=true); templates are instantiated via CreateGuardrailFromTemplate, never mutated. An update that changes the provider or the configuration of a rule on a bedrockguardrails provider, or turns such a rule on, is refused with FAILED_PRECONDITION while a data plane serving the rule's scope reports a build older than 0.11.0, a build that cannot be read, or no build. The response's warnings carry non-fatal advisories, such as a binding to a guardrail's DRAFT.
Request fields:
| Field | Required | Description |
|---|---|---|
customer_id | no | Owning customer scope; defaults to caller's session customer when empty. |
project_id | no | Owning project scope; defaults to caller's session project when empty. |
guardrail_id | yes | Required: parent guardrail id (must match rule.guardrail_id when both are set). |
rule | yes | Required: rule to update. rule.id must be set. Partial update semantics: omitted/empty scalar string fields leave the existing value untouched; enum fields set to *_UNSPECIFIED leave the existing value untouched; absent message fields (triggered_response, configuration) leave the existing value untouched; a present configuration Struct REPLACES the stored configuration wholesale (no deep merge). |
scope | no | The level this request names (tetrateio/fraser#9666). Unspecified reads as GUARDRAIL_SCOPE_PROJECT, so a client written before #9666 behaves exactly as it did. GUARDRAIL_SCOPE_ORGANIZATION requires project_id to be empty. An HTTP/JSON caller uses the binding with no /projects/{project_id} segment, because the project path requires that segment, and names the scope explicitly on top of it: scope=GUARDRAIL_SCOPE_ORGANIZATION as a query parameter on a GET or DELETE, and as a body field on a POST or PATCH. The binding fills customer_id only, so a request on it that leaves scope unset is refused as a project request naming no project. |
Response fields:
| Field | Required | Description |
|---|---|---|
rule | no | The updated rule with server-assigned fields populated. |
warnings | no | Non-fatal advisories about the rule as stored, such as a Bedrock guardrail bound to its DRAFT version. Empty when there is nothing to report. |
{"signatures":{"go":"c.Guardrails().UpdateGuardrailRule(ctx, \u0026guardrailsv1.UpdateGuardrailRuleRequest{...})","python":"client.guardrails.updateguardrailrule(...)","typescript":"client.guardrails.updateguardrailrule({...})","cli":"tare api guardrails rules update --guardrail-id $GUARDRAIL_ID --rule $RULE","curl":"curl -X PATCH \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H.../rules/01H...\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"rule\": {},\n \"scope\": \"...\"\n }'"},"examples":{"go":"// No Go SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","python":"# No Python SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","typescript":"// No TypeScript SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","cli":"tare api guardrails rules update --guardrail-id $GUARDRAIL_ID --rule $RULE","curl":"curl -X PATCH \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H.../rules/01H...\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"rule\": {},\n \"scope\": \"...\"\n }'"},"persona":"Admin","httpVerb":"PATCH","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/guardrails/{guardrail_id}/rules/{rule.id}","slug":"update-a-guardrail-rule"}
Delete a guardrail rule
Changed in v0.7.0 (behaviour changes): A project owner now creates, edits and deletes the guardrails and guardrail rules of a project they own, without an organization-wide guardrails credential. The shared pattern library and the external guardrail providers stay administrator-only, and a project owner still reaches no other project's guardrails.
What it does: Soft-deletes a rule (sets deleted_at; the row disappears from List/Get). Historical trigger records referencing this rule REMAIN queryable. Returns NOT_FOUND when the rule does not exist under the given guardrail_id. Returns PERMISSION_DENIED when the target rule's parent guardrail is a template (is_template=true); templates are instantiated via CreateGuardrailFromTemplate, never mutated.
Request fields:
| Field | Required | Description |
|---|---|---|
customer_id | no | Owning customer scope; defaults to caller's session customer when empty. |
project_id | no | Owning project scope; defaults to caller's session project when empty. |
guardrail_id | yes | Required: parent guardrail id. |
id | yes | Required: uuid of the rule to delete. |
scope | no | The level this request names (tetrateio/fraser#9666). Unspecified reads as GUARDRAIL_SCOPE_PROJECT, so a client written before #9666 behaves exactly as it did. GUARDRAIL_SCOPE_ORGANIZATION requires project_id to be empty. An HTTP/JSON caller uses the binding with no /projects/{project_id} segment, because the project path requires that segment, and names the scope explicitly on top of it: scope=GUARDRAIL_SCOPE_ORGANIZATION as a query parameter on a GET or DELETE, and as a body field on a POST or PATCH. The binding fills customer_id only, so a request on it that leaves scope unset is refused as a project request naming no project. |
{"signatures":{"go":"c.Guardrails().DeleteGuardrailRule(ctx, \u0026guardrailsv1.DeleteGuardrailRuleRequest{...})","python":"client.guardrails.deleteguardrailrule(...)","typescript":"client.guardrails.deleteguardrailrule({...})","cli":"tare api guardrails rules delete --guardrail-id $GUARDRAIL_ID \u003cid\u003e","curl":"curl -X DELETE \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H.../rules/01H...\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"examples":{"go":"// No Go SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","python":"# No Python SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","typescript":"// No TypeScript SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","cli":"tare api guardrails rules delete --guardrail-id $GUARDRAIL_ID \u003cid\u003e","curl":"curl -X DELETE \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails/01H.../rules/01H...\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"persona":"Admin","httpVerb":"DELETE","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/guardrails/{guardrail_id}/rules/{id}","slug":"delete-a-guardrail-rule"}
Get a project's effective guardrail stack
Changed in v0.7.0 (new features): A project's effective guardrail stack now reads as one list carrying both levels. A rule set at the organization and a rule set at the project that check the same thing at the same stage are marked as duplicating each other rather than one being merged away, because the data plane evaluates both. Rules that are present and switched off stay on the list, marked unenforced.
What it does: Returns every rule a project is served under, at both levels, in one list (tetrateio/fraser#9666). The two levels are not merged. A rule set at the organization and a rule set at the project that check the same thing at the same stage are two rules and the data plane evaluates both, so each is marked as duplicating the other rather than one of them being folded away. A data plane's own network controls are absent from the answer. A data plane carries no guardrails, and what it does carry is mirrored read-only.
Request fields:
| Field | Required | Description |
|---|---|---|
customer_id | no | Owning customer scope; defaults to caller's session customer when empty. |
project_id | yes | Required: the project whose stack this is. The stack is a project reading: the organization's own rules are the outer half of it, and asking for the organization alone is ListGuardrails at that scope. |
Response fields:
| Field | Required | Description |
|---|---|---|
rules | no | Every rule the project is served under, organization rules first and each level ordered by guardrail and then by rule, so two reads of an unchanged stack render identically. |
organization_rules | no | How many of them were set at each level, so a console can label the two halves without counting the list itself. |
project_rules | no | undocumented |
duplicated_rules | no | How many rules have at least one duplicate on the stack. |
{"signatures":{"go":"c.Guardrails().GetEffectiveStack(ctx, \u0026guardrailsv1.GetEffectiveStackRequest{...})","python":"client.guardrails.geteffectivestack(...)","typescript":"client.guardrails.geteffectivestack({...})","cli":"tare api guardrails effective-stack --project-id $PROJECT_ID","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails:effectiveStack\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"examples":{"go":"// No Go SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","python":"# No Python SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","typescript":"// No TypeScript SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","cli":"tare api guardrails effective-stack --project-id $PROJECT_ID","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../guardrails:effectiveStack\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"persona":"Admin","httpVerb":"GET","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/guardrails:effectiveStack","slug":"get-a-projects-effective-guardrail-stack"}
Count what a guardrail apply reconverges
Changed in v0.7.0 (new features): A guardrail apply can now state what it reconverges before you confirm it: how many projects it changes, how many distinct data planes re-pull, and how many of those projects are served nowhere.
What it does: Counts what an apply reconverges, before the operator confirms it (tetrateio/fraser#9666). An organization-level apply names no project and reaches every one of them, so it is counted in projects and in data planes: every data plane labelled with any of those projects re-pulls at once.
Request fields:
| Field | Required | Description |
|---|---|---|
customer_id | no | Owning customer scope; defaults to caller's session customer when empty. |
project_id | no | Owning project scope; empty at the organization. |
scope | no | The level the apply is at (tetrateio/fraser#9666). Unspecified reads as GUARDRAIL_SCOPE_PROJECT. |
Response fields:
| Field | Required | Description |
|---|---|---|
blast_radius | no | undocumented |
{"signatures":{"go":"c.Guardrails().GetBlastRadius(ctx, \u0026guardrailsv1.GetBlastRadiusRequest{...})","python":"client.guardrails.getblastradius(...)","typescript":"client.guardrails.getblastradius({...})","cli":"tare api guardrails blast-radius","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../guardrails:blastRadius\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"examples":{"go":"// No Go SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","python":"# No Python SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","typescript":"// No TypeScript SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","cli":"tare api guardrails blast-radius","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../guardrails:blastRadius\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\""},"persona":"Admin","httpVerb":"GET","httpPath":"/v1/customers/{customer_id}/guardrails:blastRadius","slug":"count-what-a-guardrail-apply-reconverges"}
Test a candidate rule against a project's stack
Changed in v0.7.0 (new features): A candidate guardrail rule can now be tested against a project's stack before it takes traffic. The answer names the checks it duplicates, whether it blocks what another rule only redacts, whether its provider is one its scope may bind and is switched on, whether the patterns it names resolve, and whether a data plane would evaluate it at all. Nothing is stored and no traffic is sent.
What it does: Evaluates a candidate rule against a project's effective stack and returns what it would run into, without storing it and without sending any traffic (tetrateio/fraser#9666). What it answers is where the rule lands: which checks on the stack it duplicates, whether its provider is one its scope may bind and is switched on, whether the patterns it names resolve, and whether a data plane would evaluate it at all. That turns a rollout into a countdown rather than leaving an operator to find out from a refused request.
Request fields:
| Field | Required | Description |
|---|---|---|
customer_id | no | Owning customer scope; defaults to caller's session customer when empty. |
project_id | no | Owning project scope; empty at the organization. |
scope | no | The level the candidate rule would be set at. |
rule | yes | Required: the candidate rule. It is not stored, and an id on it is ignored except to leave the rule it names out of the stack it is tested against, so editing a rule does not report it as duplicating itself. The cli field annotation is what makes protoc-gen-ia-cli emit a protojson flag for it. A REQUIRED message field carrying no such annotation is skipped, so the command would take every scalar flag, send no rule at all and be refused for the one field it exists to carry. |
guardrail_id | no | The guardrail the rule would join. Optional: a candidate for a guardrail that does not exist yet is tested as though its guardrail were enabled. |
against_project_id | no | Which project's stack to test against. Required at the organization, where the candidate reaches every project and the answer differs per project; ignored at project scope, where project_id already names it. |
Response fields:
| Field | Required | Description |
|---|---|---|
findings | no | What the candidate would run into, ordered by the enum. An empty list is the claim that it lands on a stack it does not collide with. |
duplicates | no | The rules already on the stack that evaluate the candidate's check at its stage. Both would run. |
unresolved_pattern_names | no | Pattern names the candidate references that no pattern row in its scope defines. |
would_be_enforced | no | Whether a data plane would evaluate the candidate at all: its guardrail is enabled, the rule is active and in enforce mode, and its provider is one this scope may bind and is switched on. |
stack_rules_after | no | How many rules the project's stack carries with the candidate on it, so a console can state the before and after without re-reading the stack. |
{"signatures":{"go":"c.Guardrails().TestRuleAgainstStack(ctx, \u0026guardrailsv1.TestRuleAgainstStackRequest{...})","python":"client.guardrails.testruleagainststack(...)","typescript":"client.guardrails.testruleagainststack({...})","cli":"tare api guardrails rules test-against-stack --rule $RULE","curl":"curl -X POST \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../guardrails/rules:testAgainstStack\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"project_id\": \"...\",\n \"scope\": \"...\",\n \"rule\": {},\n \"guardrail_id\": \"...\",\n \"against_project_id\": \"...\"\n }'"},"examples":{"go":"// No Go SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","python":"# No Python SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","typescript":"// No TypeScript SDK wrapper for GuardrailsService yet -- use the CLI or curl example below.","cli":"tare api guardrails rules test-against-stack --rule $RULE","curl":"curl -X POST \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../guardrails/rules:testAgainstStack\" \\\n -H \"Authorization: Bearer ak-${AGENTROUTER_API_KEY}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"project_id\": \"...\",\n \"scope\": \"...\",\n \"rule\": {},\n \"guardrail_id\": \"...\",\n \"against_project_id\": \"...\"\n }'"},"persona":"Admin","httpVerb":"POST","httpPath":"/v1/customers/{customer_id}/guardrails/rules:testAgainstStack","slug":"test-a-candidate-rule-against-a-projects-stack"}