# Manage policies

Use this page for post-genesis policy operations. For policy mechanics, see [Policies](/products/custody/governance/policies). For launch design, see [Design your policies](/products/custody/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/reference/api/openapi/intents/createintent) |
| Dry run a policy intent | [Perform a dry run](/products/custody/reference/api/openapi/intents/intentdryrun) |
| List policies | [List policies](/products/custody/reference/api/openapi/policies/getpolicies) |
| Get policy details | [Get policy details](/products/custody/reference/api/openapi/policies/getpolicy) |
| Check remaining approvers | [Get remaining users](/products/custody/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/governance/intents/manage-intents-and-approvals), [Sign intents](/products/custody/identity-and-access/authentication/authenticate-api-requests#signing-intents-state-mutation-operations), and [Check updates](/products/custody/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. Complete the **General information**, **Conditions**, **Workflow**, and **Summary** pages.
4. Click **Submit for approval**.
5. Sign the operation with the mobile app.


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

### General information

Enter a policy name, an optional description of up to 200 characters that states the rule the policy enforces, and the policy rank. Optionally, add custom properties as name-value pairs. The policy ID is generated and cannot be changed. For help choosing a rank, see [Rank guidance](/products/custody/governance/policies/reference#rank-guidance).

The initial lock status is **Unlocked**, so the policy starts matching intents as soon as it is created. Turn on the lock to create the policy in a locked state instead.

### Conditions

The **Conditions** page defines which intents the policy can match:

1. Select the **Governing scope**: **Self** applies the policy to intents in the current domain, **Descendants** applies it to intents in its subdomains, and **Self and Descendants** applies it to both.
2. Select the intent types managed by the policy. Choose **All intent types** to create a catch-all policy, or choose **Specific intent types** and select the operations and administration intent types that the policy manages. For all selectable intent types, see [Intent types in the UI](/products/custody/governance/policies/reference#intent-types-in-the-ui).
3. Under **Additional conditions**, keep **Without** if intent type and scope are the only matching criteria, or select **With** to add conditions that the intent must also fulfill.


To add a condition, select a condition type, complete its fields, and click **Add condition**. Combine conditions with **AND** (the intent must fulfill both) or **OR** (the intent can fulfill either). Use the **Preview** tab to review the conditions in JSON format, and click **Clear** to remove all conditions and start over.

For all condition types, see [Condition types in the UI](/products/custody/governance/policies/reference#condition-types-in-the-ui). For the JavaScript syntax used in custom conditions, see [JavaScript rules for conditions](/products/custody/governance/policies/reference#javascript-rules-for-conditions).

### Workflow

On the **Workflow** page, select **Approval workflow** to require approvals in one or more steps, **Always reject** to reject matching intents without user intervention, or **Always approve** to approve them without user approvals. For how each option maps to the policy's `workflow` field, see [Workflow options in the UI](/products/custody/governance/policies/reference#workflow-options-in-the-ui).

To build an approval workflow, enter the number of required approvals and select the user role that provides them. Click **Add condition** to add another approval group to the step, and combine the groups with **AND** (both groups must approve) or **OR** (either group can approve). Click **Add step** to add a sequential step.

The intent submitter counts as the first approver, so include the submitter's user role in the first step. For all workflow rules, including system-signed behavior, see [Workflow objects](/products/custody/governance/policies/reference#workflow-objects).

### Summary

The **Summary** page shows the policy details, conditions, and approval workflow. Click **See more** to expand each workflow step. Review the policy, then click **Submit for approval**.

## 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/reference/api/openapi/intents/intentdryrun) operation and can be signed and submitted with the [Propose an intent](/products/custody/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 `context.submitter.custodyRoles.includes(...)` with a `context.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-service` 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": "context.submitter.type === 'Service' && context.submitter.custodyRoles.includes('gas-station-service') && context.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/governance/policies/reference). For reusable models, see [Policy examples](/products/custody/governance/policies/examples).