Create Policy Rules
Overview
Policies add a layer of security by requiring that certain conditions are met before sensitive actions, like a withdrawal, are executed. For example, you can create a policy that requires withdrawals over a certain amount are approved by at least two admins. This policy prevents a single compromised account or a rogue actor from draining funds.
Two policies are enabled 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) on 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 [email protected].
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. | Withdraw initiated by a specific user |
| 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
- Set Up Child Enterprises
- Complete KYC Verification or Complete KYB Verification
- Create Go Accounts
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
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
{
"scopes": [
{
"id": "c8234a0f-7722-44d7-bedc-bfded7bd24a7",
"name": "wallet.segregated",
"label": "Wallet",
"description": "A BitGo Wallet",
"conditions": [
{
"name": "wallet.type",
"label": "Wallet Type",
"description": "Allows creating a Condition based on the Wallet Type",
"status": "ACTIVE",
"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": "Self-custody cold 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",
"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",
"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
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.
{
"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
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 you it requires approval, the policy rule remains in the PENDING_APPROVAL status until a wallet admin approves it.
{
"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,
"touchpointId": "166082ab-9268-4369-996a-b4ac63f6f634",
"scopeId": "c8234a0f-7722-44d7-bedc-bfded7bd24a7",
"touchpointLabel": "Withdrawal",
"scopeLabel": "Wallet",
"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"
}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
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
{
"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
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"'"
}'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.
{
"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 endpoint.
See Also
Updated about 4 hours ago