> ## Documentation Index
> Fetch the complete documentation index at: https://docs.barndoor.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Managing Policies

> Step-by-step guide to validate, create, activate, update, clone, and audit policies with the v2 API.

Barndoor policies define which MCP tools an agent can use and under what conditions. This guide walks through the full policy lifecycle with the v2 API, from drafting a policy to activating it, revising it, and reviewing its history.

<Note>
  **Estimated Time**: 15-20 minutes
</Note>

## Before You Begin

Before getting started with policy management, you’ll need:

* A Barndoor account with **admin privileges**
* A valid bearer token for the Barndoor API
* At least one registered MCP server
* At least one registered agent or application

Example shell setup:

```bash theme={null}
export BASE_URL="https://your-org.platform.barndoor.ai"
export TOKEN="your-jwt"
export MCP_SERVER_ID="server_123"
export APP_ID="agent_456"
```

<Info>
  The v2 policy API replaces the older policy-style wrapper. In v2, you send a single policy object directly to `/api/v2/policies`, use `application_ids` to scope the policy, and define each rule with `authorized`, `actions`, `roles_groups`, and optional `condition`.
</Info>

## What You’ll Learn

In this guide, you will:

* Validate policy scope before creation
* Create a policy in `DRAFT`
* Review and activate the policy
* Update rules and metadata safely
* List, search, and summarize policies
* Audit policy changes through revisions
* Clone and retire policies as part of normal lifecycle management

## Step-by-Step Guide

### Step 1: Validate your policy before creating it

Validate checks whether the policy name is unique and whether an active policy would overlap with the same MCP server and application scope.

<Expandable title="Validation request example">
  ```bash theme={null}
  curl -X POST "$BASE_URL/api/v2/policies/validate" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Slack outbound policy",
      "mcp_server_id": "'"$MCP_SERVER_ID"'",
      "application_ids": ["'"$APP_ID"'"]
    }'
  ```

  Typical response:

  ```json theme={null}
  {
    "name_is_unique": true,
    "no_overlap_if_active": true,
    "overlapping_policy_names": []
  }
  ```
</Expandable>

<Tip>
  Use `exclude_policy_id` when validating an update to an existing policy so the current record is ignored during overlap checks.
</Tip>

Reference: [`POST /api/v2/policies/validate`](/api-reference/policies/validatePolicy)

### Step 2: Create the policy as a draft

In v2, the request body is a single policy object. There is no `resourcePolicy` wrapper.

<Expandable title="Draft policy payload example">
  ```bash theme={null}
  curl -X POST "$BASE_URL/api/v2/policies" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Slack outbound policy",
      "description": "Default outbound Slack controls for the support agent.",
      "support_contact": "platform@company.com",
      "tags": ["slack", "support"],
      "status": "DRAFT",
      "mcp_server_id": "'"$MCP_SERVER_ID"'",
      "application_ids": ["'"$APP_ID"'"],
      "rules": [
        {
          "name": "allow_all",
          "authorized": true,
          "actions": ["*"],
          "roles_groups": ["*"]
        },
        {
          "name": "block_general_channel",
          "authorized": false,
          "actions": ["tools/call:chat_postMessage"],
          "roles_groups": ["*"],
          "condition": {
            "match": {
              "all": {
                "of": [
                  {
                    "expr": "request.resource.attr.channel == \"general\""
                  }
                ]
              }
            }
          }
        }
      ]
    }'
  ```
</Expandable>

Important v2 fields:

* `name`: Unique policy name within the organization
* `mcp_server_id`: MCP server this policy controls
* `application_ids`: Agents or applications this policy applies to
* `status`: `DRAFT`, `ACTIVE`, `INACTIVE`, or `ARCHIVED`
* `rules`: Array of policy rules

Reference: [`POST /api/v2/policies`](/api-reference/policies/createPolicy)

### Step 3: Understand the v2 rule model

Each rule in v2 uses a simpler structure than the older effect-based format.

<Expandable title="Rule model details">
  * `authorized: true` means allow
  * `authorized: false` means deny
  * `actions` defines which MCP actions the rule applies to
  * `roles_groups` controls which role or group matchers apply
  * `condition` adds optional fine-grained logic

  Use `roles_groups: ["*"]` when a rule should apply to every user. To target a specific IdP group, use the exact group name that Barndoor receives from your IdP, for example `roles_groups: ["Finance"]`.

  <Warning>
    Group-based policy rules only work after your IdP sends group membership to Barndoor during login. For OIDC IdPs, configure a `groups` claim in the ID token or UserInfo response and verify users have signed in again after the claim was added.
  </Warning>

  Single-expression condition:

  ```json theme={null}
  {
    "condition": {
      "match": {
        "expr": "request.resource.attr.channel == \"general\""
      }
    }
  }
  ```

  Nested condition with `all`:

  ```json theme={null}
  {
    "condition": {
      "match": {
        "all": {
          "of": [
            { "expr": "request.resource.attr.channel == \"general\"" },
            { "expr": "request.principal.id == \"agent_456\"" }
          ]
        }
      }
    }
  }
  ```
</Expandable>

### Step 4: Review the created policy

Capture the returned `policy.id` from the create response, then fetch the full policy document.

<Expandable title="Fetch a policy by ID">
  ```bash theme={null}
  curl -H "Authorization: Bearer $TOKEN" \
    "$BASE_URL/api/v2/policies/POLICY_ID"
  ```
</Expandable>

Confirm the following before rollout:

* The `status` is still `DRAFT`
* The correct `application_ids` are attached
* The `mcp_server_id` is correct
* The returned `rules` match your intended behavior

Reference: [`GET /api/v2/policies/{policy_id}`](/api-reference/policies/getPolicy)

### Step 5: Activate or update the policy

Once reviewed, move the policy into `ACTIVE`.

<Expandable title="Activation and update examples">
  ```bash theme={null}
  curl -X PATCH "$BASE_URL/api/v2/policies/POLICY_ID" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "status": "ACTIVE"
    }'
  ```

  You can also update metadata and rules through the same endpoint:

  ```bash theme={null}
  curl -X PATCH "$BASE_URL/api/v2/policies/POLICY_ID" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "description": "Blocks posting to #general while allowing all other Slack tools.",
      "tags": ["slack", "support", "production"],
      "rules": [
        {
          "name": "allow_all",
          "authorized": true,
          "actions": ["*"],
          "roles_groups": ["*"]
        },
        {
          "name": "block_general_channel",
          "authorized": false,
          "actions": ["tools/call:chat_postMessage"],
          "roles_groups": ["*"],
          "condition": {
            "match": {
              "all": {
                "of": [
                  {
                    "expr": "request.resource.attr.channel == \"general\""
                  }
                ]
              }
            }
          }
        }
      ]
    }'
  ```
</Expandable>

Reference: [`PATCH /api/v2/policies/{policy_id}`](/api-reference/policies/updatePolicy)

### Step 6: List, search, and summarize policies

List policies:

<Expandable title="List and search examples">
  ```bash theme={null}
  curl -H "Authorization: Bearer $TOKEN" \
    "$BASE_URL/api/v2/policies?page=1&limit=20"
  ```

  Search and filter:

  ```bash theme={null}
  curl -H "Authorization: Bearer $TOKEN" \
    "$BASE_URL/api/v2/policies?search=slack&status=ACTIVE&mcp_server_id=$MCP_SERVER_ID&agent_id=$APP_ID"
  ```

  Get status counts:

  ```bash theme={null}
  curl -H "Authorization: Bearer $TOKEN" \
    "$BASE_URL/api/v2/policies/summary"
  ```

  Get filter definitions for a UI:

  ```bash theme={null}
  curl -H "Authorization: Bearer $TOKEN" \
    "$BASE_URL/api/v2/policies/filter-definitions"
  ```
</Expandable>

References:

* [`GET /api/v2/policies`](/api-reference/policies/listPolicies)
* [`GET /api/v2/policies/summary`](/api-reference/policies/getPoliciesSummary)
* [`GET /api/v2/policies/filter-definitions`](/api-reference/policies/getFilterDefinitions)

### Step 7: Review revision history

Every meaningful change is available through the revisions endpoint.

<Expandable title="Revision history example">
  ```bash theme={null}
  curl -H "Authorization: Bearer $TOKEN" \
    "$BASE_URL/api/v2/policies/POLICY_ID/revisions?changes_summary=true&page=1&limit=10"
  ```
</Expandable>

Use revisions to:

* Review what changed
* See who changed it
* Understand when the policy moved between lifecycle states

Reference: [`GET /api/v2/policies/{policy_id}/revisions`](/api-reference/policies/listPolicyRevisions)

### Step 8: Clone, deactivate, or archive a policy

Clone a policy to create a safe variation without rebuilding the rule set:

<Expandable title="Clone and retirement examples">
  ```bash theme={null}
  curl -X POST "$BASE_URL/api/v2/policies/POLICY_ID/clone" \
    -H "Authorization: Bearer $TOKEN"
  ```

  The cloned policy should be reviewed and edited before activation.

  To retire a policy gradually, move it to `INACTIVE`:

  ```bash theme={null}
  curl -X PATCH "$BASE_URL/api/v2/policies/POLICY_ID" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "status": "INACTIVE"
    }'
  ```

  To remove it from normal circulation, move it to `ARCHIVED`:

  ```bash theme={null}
  curl -X PATCH "$BASE_URL/api/v2/policies/POLICY_ID" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
    "status": "ARCHIVED"
    }'
  ```
</Expandable>

References:

* [`POST /api/v2/policies/{policy_id}/clone`](/api-reference/policies/clonePolicy)
* [`PATCH /api/v2/policies/{policy_id}`](/api-reference/policies/updatePolicy)

## Legacy Endpoints

The older engine-level toggles still exist:

<Expandable title="Legacy endpoint references">
  * [`PUT /api/policy/enable`](/api-reference/policies/enable)
  * [`PUT /api/policy/disable`](/api-reference/policies/disable)
  * [`PUT /api/policies/restrictions/enable/{restriction_name}`](/api-reference/policies/enableRestriction)
  * [`PUT /api/policies/restrictions/disable/{restriction_name}`](/api-reference/policies/disableRestriction)
</Expandable>

<Warning>
  For new policy lifecycle workflows, prefer the v2 endpoints and the `status` field. Use the legacy endpoints only when you explicitly need the older engine-level toggles.
</Warning>

## Best Practices

* Create policies as `DRAFT` first, then promote to `ACTIVE`
* Validate before both create and update operations
* Keep `application_ids` narrow to avoid overlap with other active policies
* Use descriptive tags and a `support_contact` so ownership is clear
* Review revisions instead of maintaining a separate manual change log
* Clone stable policies before making large behavior changes
