# Create Policy Rules

Source: https://developers.bitgo.com/docs/crypto-as-a-service-policies

## Overview

Policies add a layer of security by requiring that certain conditions occur before sensitive actions, like a withdrawal, execute. For example, you can create a policy that requires at least two admins approve withdrawals over a certain amount. This policy prevents a single compromised account or a rogue actor from draining funds.

BitGo enables two policies by default:

* **Bitgo Video ID** - All withdrawals above the withdrawal threshold limit of $250,000 require Video ID Verification.
* **Bitgo Unverified Address** - All addresses must be whitelisted and verified for Go Accounts.

You can create additional policies. Policy rules define what must occur (**actions**) before users can execute sensitive operations (**touchpoints**). Rules apply to things within your enterprise (**scopes**) during specific scenarios (**conditions**).

> 📘 **Note**
> 
> As a security measure, BitGo locks all policies 48 hours after you create them. To modify an existing locked policy, contact support@bitgo.com.

### Important Terms

| Term | Description | Example |
| :--- | :---------- | :------ |
| **Scope** | An entity, or set of entities, that you can control using a policy rule. | Go Accounts |
| **Touchpoint** | An event that can occur on a scope and can trigger a policy rule. | Withdrawals |
| **Condition** | Defines the exact criteria surrounding the touchpoint that's required to trigger the policy. | A specific user initiates the withdrawal |
| **Action** | Something that must occur for the touchpoint to complete or something that automatically occurs, completing the touchpoint. | Require approval from specific users or automatic approval |

## Prerequisites

* [Set Up Organization](/docs/crypto-as-a-service-organization)
* [Set Up Child Enterprises](/docs/crypto-as-a-service-child-enterprises)
* [Complete KYC Verification](/docs/crypto-as-a-service-know-your-customer) or [Complete KYB Verification](/docs/crypto-as-a-service-know-your-business)
* [Create Go Accounts](/docs/crypto-as-a-service-go-accounts)

## Cookbook

Need just the steps? Expand the cookbook below to get started:

<Cookbook slug="caas-policies" title="Create CaaS Policy Rules" />

## 1. Get Scope ID

Before you can create a policy rule, you must get the scope ID for the scope you want to create the rule for.

>Endpoint: [List Scopes](/reference/v1policyscopelist)

```shell cURL
export ENTERPRISE_ID="<YOUR_ENTERPRISE_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"

curl -X GET \
  "https://app.bitgo-test.com/api/policy/v1/enterprises/$ENTERPRISE_ID/scopes" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

#### Step Result

```json JSON
{
  "scopes": [
    {
      "id": "c8234a0f-7722-44d7-bedc-bfded7bd24a7",
      "name": "wallet.segregated",
      "label": "Wallet",
      "description": "A BitGo Wallet",
      "bitgoManaged": false,
      "conditions": [
        {
          "name": "wallet.type",
          "label": "Wallet Type",
          "description": "Allows creating a Condition based on the Wallet Type",
          "status": "ACTIVE",
          "bitgoManaged": false,
          "isPortable": true,
          "parameters": [
            {
              "name": "walletType",
              "label": "Type",
              "description": "The Wallet Type",
              "type": "ENUMERATED",
              "required": "ALWAYS",
              "allowMultiple": true,
              "values": [
                {
                  "value": "custodial",
                  "label": "Custody Wallet",
                  "description": "A custody wallet"
                },
                {
                  "value": "hot",
                  "label": "Hot Wallet",
                  "description": "A hot wallet"
                },
                {
                  "value": "cold",
                  "label": "BitGo Offline Vault wallet",
                  "description": "A cold wallet"
                },
                {
                  "value": "trading",
                  "label": "Go Account",
                  "description": "A trading wallet"
                }
              ]
            }
          ]
        },
        {
          "name": "wallet.ids",
          "label": "Single Wallet",
          "description": "Allows creating a Condition based on the Wallet Id",
          "status": "ACTIVE",
          "bitgoManaged": false,
          "isPortable": false,
          "parameters": [
            {
              "name": "walletId",
              "label": "Wallet Id",
              "description": "The Wallet Ids",
              "type": "BITGO_WALLET_ID",
              "required": "ALWAYS",
              "allowMultiple": false,
              "values": []
            }
          ]
        },
        {
          "name": "wallet.all",
          "label": "All wallets in my enterprise",
          "description": "Applies to All Wallets",
          "status": "ACTIVE",
          "bitgoManaged": false,
          "isPortable": true,
          "parameters": []
        }
      ]
    }
  ]
}
```

## 2. Get Touchpoint Name

Using the scope ID returned in the prior step, you can now list all the available touchpoints for the given scope.

>Endpoint: [List Touchpoints](/reference/v1policyscopetouchpointlist)

```shell cURL
export ENTERPRISE_ID="<YOUR_ENTERPRISE_ID>"
export SCOPE_ID="<SCOPE_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"

curl -X GET \
  "https://app.bitgo-test.com/api/policy/v1/enterprises/$ENTERPRISE_ID/scopes/$SCOPE_ID/touchpoints" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

#### Step Result

You return all possible touchpoints for the given scope. Save the touchpoint name that you want to create a policy rule for, because you must pass it in the following step.

```json JSON
{
  "touchpoints": [
    {
      "id": "166082ab-9268-4369-996a-b4ac63f6f634",
      "name": "wallet.segregated.transfer",
      "status": "ACTIVE",
      "label": "Withdrawal",
      "description": "Withdrawal from a BitGo Wallet",
      "adminOnly": false
    },
    {
      "id": "0e0c1126-daf3-4b79-a05c-094ebd30007d",
      "name": "goaccount.settlement.signed",
      "status": "ACTIVE",
      "label": "Settlement Initiated",
      "description": "When a settlement is initiated from a BitGo Go Account Wallet",
      "adminOnly": false
    },
    {
      "id": "8c0a1a3f-7f20-4ff1-aa8a-ac28a217f3f3",
      "name": "goaccount.settlement.countersigned",
      "status": "ACTIVE",
      "label": "Settlement Approved",
      "description": "When a settlement is accepted by a user on a BitGo Go Account Wallet",
      "adminOnly": false
    }
  ],
  "page": 1,
  "totalPages": 1,
  "totalElements": 3
}
```

## 3. Create Policy Rule

Using the touchpoint name returned in the prior step, you can now create a policy rule for the given touchpoint. The following example creates a policy rule that requires approval from a specific user for withdrawals of more than $100 from a specific wallet.

>Endpoint: [Create Policy Rule](/reference/v1policyrulecreate)

```shell cURL
export ENTERPRISE_ID="<YOUR_ENTERPRISE_ID>"
export TOUCHPOINT="<TOUCHPOINT_NAME>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export USER_ID="<APPROVER_USER_ID>"
export WALLET_ID="<WALLET_ID>"

curl -X POST \
  "https://app.bitgo-test.com/api/policy/v1/enterprises/$ENTERPRISE_ID/touchpoints/$TOUCHPOINT/rules" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "name": "Spending limit - require approval on withdrawals of more than 100 USD",
    "adminOnly": false,
    "clauses": [
        {
            "conditions": [
                {
                    "name": "transfer.amount",
                    "parameters": {
                        "operator": ">",
                        "amount": "100",
                        "coin": "usd"
                    }
                }
            ],
            "actions": [
                {
                    "name": "approvals.customer.enterpriseUser",
                    "parameters": {
                        "userIds": [
                            "'"$USER_ID"'"
                        ],
                        "minRequired": "1",
                        "initiatorIsAllowedToApprove": false
                    }
                }
            ]
        }
    ],
    "filteringConditions": [
        {
            "name": "wallet.ids",
            "parameters": {
                "walletId": [
                    "'"$WALLET_ID"'"
                ]
            }
        }
    ]
}'
```

#### Step Result

The new policy rule enters a `PENDING_APPROVAL` status. If the new policy rule doesn't require approval, it automatically updates to `ACTIVE` status within a short period of time. If it requires approval, the policy rule remains in the `PENDING_APPROVAL` status until a wallet admin approves it.

```json JSON
{
  "uniqueId": "835c75f8-49e2-4d5b-82f0-0c8829d52a05",
  "id": "5e43e1b6-665d-4406-b59a-b9e1d2e9dfad",
  "name": "Spending limit - require approval on withdrawals of more than 100 USD",
  "status": "PENDING_APPROVAL",
  "adminOnly": false,
  "bitgoManaged": false,
  "touchpointId": "166082ab-9268-4369-996a-b4ac63f6f634",
  "scopeId": "c8234a0f-7722-44d7-bedc-bfded7bd24a7",
  "touchpointLabel": "Withdrawal",
  "scopeLabel": "Wallet",
  "touchpointName": "wallet.segregated.transfer",
  "clauses": [
    {
      "actions": [
        {
          "name": "approvals.customer.enterpriseUser",
          "parameters": {
            "userIds": ["62ab90e06dfda30007974f0a52a12995"],
            "minRequired": "1",
            "initiatorIsAllowedToApprove": false
          }
        }
      ],
      "conditions": [
        {
          "name": "transfer.amount",
          "parameters": {
            "operator": ">",
            "amount": "100",
            "coin": "usd"
          }
        }
      ]
    }
  ],
  "filteringConditions": [
    {
      "name": "wallet.ids",
      "parameters": { "walletId": ["654ec786c07fe8dc0dcfe03916ec5bb0"] }
    }
  ],
  "locked": false,
  "lockType": "LOCK_AFTER_DATE",
  "lockDate": "2024-04-14T18:52:07.955224Z",
  "createdDate": "2024-04-12T18:52:07.955235Z",
  "modifiedDate": "2024-04-12T18:52:08.041738Z",
  "enterpriseId": "62c5ae8174ac860007aff138a2d74df7",
  "createdBy": "62ab90e06dfda30007974f0a52a12995",
  "modifiedBy": "62ab90e06dfda30007974f0a52a12995",
  "evaluationId": "57cd4e69-8038-4568-8124-55ca80ff94c1",
  "isDuplicated": false
}
```

## 4. Approve Policy Rule (Optional)

> 📘 **Note**
>
> If you configure an approval requirement for policy rules, you can't approve your own policy-rule changes - another admin must approve them.

### 4.1 Get Pending-Approval ID

To update a pending approval, you must get the pending-approval ID for the pending approval you want to respond to.

>Endpoint: [List Pending Approvals](/reference/v2approvallist)

```shell cURL
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"

curl -X GET \
  https://app.bitgo-test.com/api/v2/pendingApprovals \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

#### Step Result

```json JSON
{
  "pendingApprovals": [
    {
      "id": "661982d8e1ee8192595fed2145490e13",
      "wallet": "654ec786c07fe8dc0dcfe03916ec5bb0",
      "enterprise": "62c5ae8174ac860007aff138a2d74df7",
      "bitgoOrg": "BitGo Trust",
      "creator": "62ab90e06dfda30007974f0a52a12995",
      "createDate": "2024-04-12T18:52:08.072Z",
      "info": {
        "type": "genericRequest",
        "genericRequest": {
          "description": "Request to create policy rule {policyRuleId}",
          "anchors": [
            {
              "key": "policyRuleId",
              "value": "835c75f8-49e2-4d5b-82f0-0c8829d52a05",
              "anchorType": "policyRuleId"
            }
          ],
          "proposedId": "835c75f8-49e2-4d5b-82f0-0c8829d52a05",
          "resourceType": "policyRule",
          "changeType": "create",
          "metadata": {
            "sharedId": "5e43e1b6-665d-4406-b59a-b9e1d2e9dfad",
            "policyRuleName": "Spending limit - require approval on withdrawals of more than 100 USD"
          }
        }
      },
      "approvers": [
        "621d08a634ad8a0007fcddffd7c429cc",
        "627ff9325a5c1b0007c05a40d15e1522"
      ],
      "state": "pending",
      "scope": "wallet",
      "userIds": [
        "62ab90e06dfda30007974f0a52a12995",
        "621d08a634ad8a0007fcddffd7c429cc",
        "627ff9325a5c1b0007c05a40d15e1522"
      ],
      "approvalsRequired": 1,
      "singleRunResults": [],
      "resolvers": [],
      "policyEvaluationId": "57cd4e69-8038-4568-8124-55ca80ff94c1",
      "actions": [
        {
          "id": "65a52063-df3b-4362-bfc1-68d4e8b2cc6f",
          "status": "PENDING",
          "name": "approvals.customer.walletAdmin",
          "parameters": { "userIds": [] },
          "resolvers": [],
          "approvers": [
            "621d08a634ad8a0007fcddffd7c429cc",
            "627ff9325a5c1b0007c05a40d15e1522"
          ]
        }
      ],
      "resolutionOrder": [
        { "actions": ["65a52063-df3b-4362-bfc1-68d4e8b2cc6f"] }
      ]
    }
  ]
}
```

### 4.2 Approve Pending Approval

>Endpoint: [Update Pending Approval](/reference/v2approvalupdate)

```shell cURL
export APPROVAL_ID="<APPROVAL_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export OTP="<YOUR_OTP>"

curl -X PUT \
  https://app.bitgo-test.com/api/v2/pendingApprovals/$APPROVAL_ID \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "state": "approved",
    "otp": "'"$OTP"'"
  }'
```
```js JavaScript
const baseCoin = this.bitgoSDK.coin(initialPendingApproval.coin);
const pendingApproval = await baseCoin.pendingApprovals().get({ id: initialPendingApproval.id });
const result = await pendingApproval.approve(params);
```

#### Step Result

You approved the policy.

```json JSON
{
  "id": "661982d8e1ee8192595fed2145490e13",
  "wallet": "654ec786c07fe8dc0dcfe03916ec5bb0",
  "enterprise": "62c5ae8174ac860007aff138a2d74df7",
  "bitgoOrg": "BitGo Trust",
  "creator": "62ab90e06dfda30007974f0a52a12995",
  "createDate": "2024-04-12T18:52:08.072Z",
  "approvedDate": "2024-04-12T18:58:29.774Z",
  "info": {
    "type": "genericRequest",
    "genericRequest": {
      "description": "Request to create policy rule {policyRuleId}",
      "anchors": [
        {
          "key": "policyRuleId",
          "value": "835c75f8-49e2-4d5b-82f0-0c8829d52a05",
          "anchorType": "policyRuleId"
        }
      ],
      "proposedId": "835c75f8-49e2-4d5b-82f0-0c8829d52a05",
      "resourceType": "policyRule",
      "changeType": "create",
      "metadata": {
        "sharedId": "5e43e1b6-665d-4406-b59a-b9e1d2e9dfad",
        "policyRuleName": "Spending limit - require approval on withdrawals of more than 100 USD"
      }
    }
  },
  "approvers": [],
  "state": "approved",
  "scope": "wallet",
  "userIds": [
    "62ab90e06dfda30007974f0a52a12995",
    "621d08a634ad8a0007fcddffd7c429cc",
    "627ff9325a5c1b0007c05a40d15e1522"
  ],
  "approvalsRequired": 1,
  "singleRunResults": [],
  "resolvers": [
    {
      "user": "627ff9325a5c1b0007c05a40d15e1522",
      "date": "2024-04-12T18:58:29.655Z",
      "resolutionType": "pending",
      "resolutionAction": "approve"
    }
  ],
  "policyEvaluationId": "57cd4e69-8038-4568-8124-55ca80ff94c1",
  "actions": [
    {
      "id": "65a52063-df3b-4362-bfc1-68d4e8b2cc6f",
      "status": "COMPLETE",
      "name": "approvals.customer.walletAdmin",
      "parameters": { "userIds": [] },
      "resolvers": [
        {
          "user": "627ff9325a5c1b0007c05a40d15e1522",
          "date": "2024-04-12T18:58:29.655Z",
          "resolutionType": "pending",
          "resolutionAction": "approve"
        }
      ],
      "approvers": ["621d08a634ad8a0007fcddffd7c429cc"]
    }
  ],
  "resolutionOrder": [{ "actions": ["65a52063-df3b-4362-bfc1-68d4e8b2cc6f"] }]
}
```

## Next Steps

You can review your new policy rule by calling the [List policy rules](/reference/v1policyruleslist) endpoint.

## See Also

* [API Reference: Create policy rule](/reference/v1policyrulecreate)
* [API Reference: List Scopes](/reference/v1policyscopelist)
* [API Reference: List Touchpoints](/reference/v1policyscopetouchpointlist)
