# Manage policies

Use this page for post-genesis policy operations. For policy mechanics, see [Policies](/products/custody/v1.36/governance/policies). For launch design, see [Design your policies](/products/custody/v1.36/governance/genesis/design-your-policies).

## Policy actions

| Action | UI procedure | API procedure |
|  --- | --- | --- |
| Create a policy | [Create a policy in the UI](#create-a-policy-in-the-ui) | [Create a policy with the API](#create-a-policy-with-the-api) |
| Create a system-signed policy | Use the API procedure. | [Create a policy for system-signed intents with the API](#create-a-policy-for-system-signed-intents-with-the-api) |
| Update a policy | [Update a policy in the UI](#update-a-policy-in-the-ui) | [Update a policy with the API](#update-a-policy-with-the-api) |
| Lock and unlock a policy | [Lock or unlock a policy in the UI](#lock-or-unlock-a-policy-in-the-ui) | [Lock or unlock a policy with the API](#lock-or-unlock-a-policy-with-the-api) |


## API reference and shared process

| Task | API reference |
|  --- | --- |
| Propose a policy intent | [Propose an intent](/products/custody/v1.36/reference/api/openapi/intents/createintent) |
| Dry run a policy intent | [Perform a dry run](/products/custody/v1.36/reference/api/openapi/intents/intentdryrun) |
| List policies | [List policies](/products/custody/v1.36/reference/api/openapi/policies/getpolicies) |
| Get policy details | [Get policy details](/products/custody/v1.36/reference/api/openapi/policies/getpolicy) |
| Check remaining approvers | [Get remaining users](/products/custody/v1.36/reference/api/openapi/intents/getremainingusers) |


Policy changes use the standard intent flow. For signing, approval, and status checks, see [Manage intents and approvals](/products/custody/v1.36/governance/intents/manage-intents-and-approvals), [Sign intents](/products/custody/v1.36/identity-and-access/authentication/authenticate-api-requests#signing-intents-state-mutation-operations), and [Check updates](/products/custody/v1.36/governance/intents/manage-intents-and-approvals#check-state).

## Common operations

| Operation | Intent type | Use when |
|  --- | --- | --- |
| Create policy | `v0_CreatePolicy` | Add a new approval rule. |
| Update policy | `v0_UpdatePolicy` | Change matching, condition, workflow, scope, rank, or metadata. |
| Lock policy | `v0_LockPolicy` | Disable a policy without deleting it. |
| Unlock policy | `v0_UnlockPolicy` | Re-enable a locked policy. |


## Create a policy in the UI

1. Go to **Policies**.
2. Click **Create a policy**.
3. Enter the policy details.
4. Click **Submit for approval**.
5. Sign the operation with the mobile app.


The policy is created after the intent is approved and executed.

Use these UI pages to enter policy details:

| Page | Details |
|  --- | --- |
| General information | Policy name, optional description, custom properties, and rank. Rank controls precedence among eligible policies. |
| Conditions | Governing scope, scope of application, intent types, standard conditions, and custom conditions. You can apply the policy to all intent types or select specific intent types. You can view conditions in JSON format in the **Preview** tab. |
| Workflows | Always-reject behavior or approval workflow with one or more steps. Each step includes an approval group and optional `AND` or `OR` approval groups. For user-signed submissions, the submitter counts as the first approver, so the first step must correspond to the user role that can create the specified entities. For system-signed proposals, the service submitter does not count as a user approval. |
| Summary | Review and submission. |


Custom conditions are JSON objects with `type` and `expression` fields. The expression is JavaScript. When the expression evaluates to `true`, the policy is eligible to apply to the intent. For condition and workflow syntax, see [Policy reference](/products/custody/v1.36/governance/policies/reference).

## Create a policy with the API

Create a policy by submitting a `v0_CreatePolicy` intent. The following dry-run request body matches the [Perform a dry run](/products/custody/v1.36/reference/api/openapi/intents/intentdryrun) operation and can be signed and submitted with the [Propose an intent](/products/custody/v1.36/reference/api/openapi/intents/createintent) operation after review.

Before you create a policy, prepare a new policy ID and a new intent ID in standard UUID format. Also confirm the role names, intent types, scope, condition paths, workflow, and rank.


```json
{
  "author": {
    "id": "6ac20654-450e-29e4-65e2-1bdecb7db7c4",
    "domainId": "9067d363-6411-498b-a32b-15d230a86706"
  },
  "expiryAt": "2026-06-30T15:30:00.000Z",
  "targetDomainId": "9067d363-6411-498b-a32b-15d230a86706",
  "id": "7d256a32-812e-4a66-9a56-42ebfac5426a",
  "payload": {
    "id": "5b440ba5-d013-11eb-8cd0-dcfb48cfb3cb",
    "alias": "policy-governance",
    "rank": 700,
    "intentTypes": [
      "v0_CreatePolicy",
      "v0_UpdatePolicy",
      "v0_LockPolicy",
      "v0_UnlockPolicy"
    ],
    "scope": "Self",
    "scriptingEngine": "Javascript_v0",
    "condition": {
      "expression": "context.references.users[context.request.author.id].roles.includes('policy-operator')",
      "type": "Expression"
    },
    "workflow": [
      {
        "left": {
          "role": "policy-operator",
          "quorum": 2,
          "type": "RoleQuorum"
        },
        "right": {
          "role": "compliance",
          "quorum": 1,
          "type": "RoleQuorum"
        },
        "type": "And"
      }
    ],
    "lock": "Unlocked",
    "description": "Controls policy lifecycle operations in the root domain.",
    "customProperties": {},
    "type": "v0_CreatePolicy"
  },
  "description": "Create policy governance policy",
  "customProperties": {},
  "type": "Propose"
}
```

Dry run before submitting:


```sh
curl -X POST "${CUSTODY_API_URL}/v1/intents/dry-run" \
  -H "Authorization: Bearer ${JWT_TOKEN}" \
  -H "Content-Type: application/json" \
  -d @create-policy-intent.json
```

Submit the signed intent:


```sh
curl -X POST "${CUSTODY_API_URL}/v1/intents" \
  -H "Authorization: Bearer ${JWT_TOKEN}" \
  -H "Content-Type: application/json" \
  -H "requestId: 8b6571b9-493c-49fb-9d92-e19b6f39f7cf" \
  -d @signed-create-policy-intent.json
```

## Update a policy

Use `v0_UpdatePolicy` to replace the mutable policy fields. Include the current policy `reference.id` and `reference.revision`, then provide the updated alias, rank, scope, scripting engine, condition, workflow, description, and custom properties.

### Update a policy in the UI

You can update only the approval workflow or update the full policy:

| Update | UI steps |
|  --- | --- |
| Approval workflow only | Go to **Policies**, open the contextual menu at the end of the policy row, select **Edit policy approval workflow**, update the workflow settings, click **Submit for approval**, and sign with the mobile app. |
| All policy details | Go to **Policies**, open the contextual menu at the end of the policy row, select **Edit policy approval workflow**, update the policy fields, click **Submit for approval**, and sign with the mobile app. |


### Update a policy with the API


```json
{
  "payload": {
    "reference": {
      "id": "5b440ba5-d013-11eb-8cd0-dcfb48cfb3cb",
      "revision": 3
    },
    "alias": "policy-governance",
    "rank": 750,
    "intentTypes": [
      "v0_CreatePolicy",
      "v0_UpdatePolicy",
      "v0_LockPolicy",
      "v0_UnlockPolicy"
    ],
    "scope": "Self",
    "scriptingEngine": "Javascript_v0",
    "condition": {
      "expression": "context.references.users[context.request.author.id].roles.includes('policy-operator')",
      "type": "Expression"
    },
    "workflow": [
      {
        "left": {
          "role": "policy-operator",
          "quorum": 2,
          "type": "RoleQuorum"
        },
        "right": {
          "role": "compliance",
          "quorum": 2,
          "type": "RoleQuorum"
        },
        "type": "And"
      }
    ],
    "description": "Controls policy lifecycle operations in the root domain.",
    "customProperties": {},
    "type": "v0_UpdatePolicy"
  }
}
```

Treat policy updates as high-risk operations. A policy update can change the policy that governs future policy updates.

## Create a policy for system-signed intents with the API

System-signed intents are API-only proposals from service callers. They are submitted without a client-side payload signature and are matched only by policies whose `intentOrigin` is `SystemSigned`.

Use this pattern only for tightly scoped automation. At minimum:

- Set `intentOrigin` to `SystemSigned`.
- Specify the exact `intentTypes` the service caller can submit.
- Use a condition that checks the service submitter. For defense in depth, combine `submitter.custodyRoles.includes(...)` with a `submitter.subject` check for the expected service account.
- Omit `workflow` only when automatic execution is intentional. If you include a workflow, user-signed approvers must satisfy it.


The following example allows a service caller with the `gas-station` custody role and `gas-station-svc` subject to submit transaction order proposals. Replace both values with the role and subject issued by your identity provider.


```json
{
  "author": {
    "id": "6ac20654-450e-29e4-65e2-1bdecb7db7c4",
    "domainId": "9067d363-6411-498b-a32b-15d230a86706"
  },
  "expiryAt": "2026-06-30T15:30:00.000Z",
  "targetDomainId": "9067d363-6411-498b-a32b-15d230a86706",
  "id": "7d256a32-812e-4a66-9a56-42ebfac5426a",
  "payload": {
    "id": "af1d2e33-9a94-4456-bcb3-895bba820d38",
    "alias": "gas-station-system-signed",
    "rank": 420,
    "intentTypes": ["v0_CreateTransactionOrder"],
    "intentOrigin": "SystemSigned",
    "scope": "SelfAndDescendants",
    "scriptingEngine": "Javascript_v0",
    "condition": {
      "expression": "submitter.type === 'Service' && submitter.custodyRoles.includes('gas-station') && submitter.subject === 'gas-station-svc'",
      "type": "Expression"
    },
    "lock": "Unlocked",
    "description": "Allows Gas Station service-submitted transaction orders.",
    "customProperties": {},
    "type": "v0_CreatePolicy"
  },
  "description": "Create system-signed Gas Station policy",
  "customProperties": {},
  "type": "Propose"
}
```

Submit this policy with the normal user-signed policy creation flow. The policy itself is a governance change and should be created, approved, and audited by users with authority to manage policies.

## Lock and unlock a policy

Lock a policy when it should stop matching new intents without being removed from the environment.

### Lock or unlock a policy in the UI

1. Go to **Policies**.
2. Open the contextual menu at the end of the policy row.
3. Select **Lock policy** or **Unlock policy**.
4. Click **Submit for approval**.
5. Sign the operation with the mobile app.


### Lock or unlock a policy with the API

Submit `v0_LockPolicy` or `v0_UnlockPolicy` with the current policy reference:


```json
{
  "payload": {
    "reference": {
      "id": "5b440ba5-d013-11eb-8cd0-dcfb48cfb3cb",
      "revision": 3
    },
    "type": "v0_LockPolicy"
  }
}
```

Use `v0_UnlockPolicy` with the same `reference` shape to re-enable the policy.

## Safe rollout sequence

Policy changes can change the rules that govern future policy changes. Use a controlled sequence:

1. Confirm domain read access and required roles.
2. Confirm enough users exist for the intended quorum.
3. Deploy operational policies before policy-governance policies.
4. Deploy policy-governance policies after the users and fallback path exist.
5. Deploy emergency "break-glass" policies, high-privilege policies used only during incidents, only after their scope and intent types are explicit.
6. Dry run representative intents.


## Pre-flight checks

| Check | Why it matters |
|  --- | --- |
| `intentTypes` are explicit | Prevents accidental catch-all behavior. |
| `intentOrigin` is intentional | Prevents a user-signed policy from being confused with a system-signed automation policy. |
| Condition paths are valid | Prevents policy selection errors. |
| Workflow is satisfiable | Prevents governance lockout. |
| User-signed first workflow step includes maker role | Lets the intent creator count as first approval. For system-signed policies, confirm the workflow can be satisfied by user approvers. |
| Rank is intentional | Ensures the expected policy wins. |
| Scope is narrow enough | Prevents parent-domain policies applying too broadly. |
| Fallback exists | Gives legitimate unexpected workflows a controlled path. |


## Common policy mistakes

| Mistake | Problem | Fix |
|  --- | --- | --- |
| Empty `workflow: []` | Matching intents are rejected. | Omit workflow for auto-approval or define explicit approval steps. |
| Missing `intentTypes` | Policy can match all intents. | Specify intent types except for deliberate fallback policies. |
| Missing `intentOrigin` on an automation policy | Policy matches only user-signed proposals. | Set `intentOrigin: "SystemSigned"` when the policy is meant for system-signed API proposals. |
| High-rank catch-all | Specific policies may never apply. | Give fallback policies low rank. |
| Required role has no users | Workflow cannot complete. | Create users before deploying the policy. |
| Role names do not match | Approvers cannot satisfy workflow. | Keep role names consistent across users and policies. |


## Operational checklist

Before submitting a policy intent:

- Confirm the target domain and policy scope.
- Confirm the policy's intent types are deliberate.
- Confirm the condition is null-safe and uses the correct payload paths for each intent type.
- Confirm every workflow role exists in the target domain.
- Confirm quorum can be satisfied by independent users.
- For user-signed policies, confirm the first workflow step includes the maker role.
- For system-signed policies, confirm the workflow can be satisfied by user approvers, or that automatic execution is intentional.
- Confirm rank relative to other matching policies.
- Dry run representative intents before and after the policy change.


## Troubleshooting

When a policy does not behave as expected:

1. Check intent type.
2. Check target domain and scope.
3. Check condition expression.
4. Check rank against other matching policies.
5. Check workflow roles and quorum.
6. Check lock state.


For field details, see [Policy reference](/products/custody/v1.36/governance/policies/reference). For reusable models, see [Policy examples](/products/custody/v1.36/governance/policies/examples).