---
title: "Create a guardrail"
method: POST
path: "/v1/projects/{project_id}/guardrails"
tags: ["Guardrails"]
---

# Create a guardrail

`POST /v1/projects/{project_id}/guardrails`

## Request

- Base URL: `https://api.naturali.ai`
- URL: `https://api.naturali.ai/v1/projects/{project_id}/guardrails`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://api.naturali.ai/authorize`, token URL `https://api.naturali.ai/token`, scopes: `mcp:access`)

Creates a new guardrail in the project, archiving its document as version 1. The `document` is validated on write: `class` must be a literal (A/B/C/D) or a JSON Logic expression, and every variable it (and `guard`) reference must resolve to the `args.*` / `context.*` / `runtime.*` namespaces — an out-of-catalog `runtime.*` key is rejected with 400.

## Request body

- CreateGuardrailRequest
  - `name` string, required: Human-readable name
  - `description` string, nullable
  - `document` GuardrailDocument, required: The action-class document. `class` maps a call to an action class; `guard` gates class-B autonomy. Both are single JSON Logic expressions over the `args.*` / `context.*` / `runtime.*` namespaces.
    - `class` union, required: A class literal (`A` / `B` / `C` / `D`) or a JSON Logic expression returning one. An invalid result resolves to `default_class`.
      - 'A' | 'B' | 'C' | 'D'
      - object
    - `default_class` 'A' | 'B' | 'C' | 'D': Applied when the `class` expression returns anything other than a valid class. Defaults to `C` (fail-closed).
    - `guard` object: A single JSON Logic expression; when the call classifies as `B` it must evaluate truthy to execute autonomously. Compose multiple conditions with `{ "and": [...] }`.
    - `escalate` boolean: When `true`, a failing guard routes to approval instead of tripping fail-closed.
    - `expires_in` integer: Default approval window in seconds for a class-C approval this guardrail files. Omitted → the platform's 24h default. When several guardrails apply, the governing (strictest-matching) one's value is used.
  - `context_tool_id` string, nullable
  - `context_mode` 'merge' | 'replace'
  - `version_label` string: Optional tag for the config version this write archives (e.g. `initial`). Annotates the version only — it is not stored on the guardrail and is not part of the config, so labelling a change is never itself a change.

## Response `201`

Guardrail created

- Guardrail
  - `id` string: Public ID of the guardrail
  - `project_id` string: Public ID of the owning project
  - `name` string: Human-readable name
  - `description` string, nullable: Optional description
  - `version` integer: Incremented on every document write; prior versions are archived
  - `document` GuardrailDocument: The action-class document. `class` maps a call to an action class; `guard` gates class-B autonomy. Both are single JSON Logic expressions over the `args.*` / `context.*` / `runtime.*` namespaces.
    - `class` union, required: A class literal (`A` / `B` / `C` / `D`) or a JSON Logic expression returning one. An invalid result resolves to `default_class`.
      - 'A' | 'B' | 'C' | 'D'
      - object
    - `default_class` 'A' | 'B' | 'C' | 'D': Applied when the `class` expression returns anything other than a valid class. Defaults to `C` (fail-closed).
    - `guard` object: A single JSON Logic expression; when the call classifies as `B` it must evaluate truthy to execute autonomously. Compose multiple conditions with `{ "and": [...] }`.
    - `escalate` boolean: When `true`, a failing guard routes to approval instead of tripping fail-closed.
    - `expires_in` integer: Default approval window in seconds for a class-C approval this guardrail files. Omitted → the platform's 24h default. When several guardrails apply, the governing (strictest-matching) one's value is used.
  - `context_tool_id` string, nullable: Optional tool the platform calls at evaluation time to fetch fresh guardrail context.
  - `context_mode` 'merge' | 'replace' | 'null', nullable: How tool-fetched context combines with the caller-supplied context.
  - `created_at` string, date-time
  - `updated_at` string, date-time

## Other responses

- `400`: Bad Request — invalid document or variable reference
- `401`: Unauthorized
- `403`: Forbidden

---

[API](https://skmtc.dev/naturali/apis/naturali-ai-api.md) · [All operations](https://skmtc.dev/naturali/apis/naturali-ai-api/llms.txt) · [OpenAPI document](https://skmtc.dev/naturali/apis/naturali-ai-api/revisions/e4905b78f422?raw)
