What is a Domain Template?
A Domain Template is a bundle of fact definitions and sample rules for one common decision, such as checkout pricing or transfer approval. Applying a template creates:- The template’s facts, registered for your tenant. An input fact with a constraint comes with its allowed values or range.
- A new policy group with the sample rules in a draft version, ready to edit and publish.
- An entry in your group list, same as if you had built it manually.
Available Templates
E-Commerce: Checkout Pricing
Fintech: Transfer Approval
SaaS: Plan Limits
Insurance: Claim Triage
AI Agent: Action Approval
E-Commerce: Checkout Pricing
One order discount per order (member tier or first-order code), a capped AI-proposed discount on top of it, free shipping, and 5% member rewards. Applying it creates the policy group E-Commerce Checkout Pricing with a draft version.Facts
Send every input fact on each request, using a neutral value when one does not apply. The rules write the output facts, so do not send those. Input factsNONE, BRONZE, SILVER, GOLD, PLATINUMRules
1. PLATINUM member: 15% off
1. PLATINUM member: 15% off
- When:
loyaltyTier = "PLATINUM" - Then:
purchaseSubtotalUsd -= 15%(rounded to 2 decimal places, HALF_UP) - Mutex group:
ecom_order_discount
2. WELCOME15: 15% off first order (USD 50+)
2. WELCOME15: 15% off first order (USD 50+)
- When:
appliedPromoCode = "WELCOME15"ANDisFirstPurchase = trueANDpurchaseSubtotalUsd ≥ 50 - Then:
purchaseSubtotalUsd -= 15%(rounded to 2 decimal places, HALF_UP) - Mutex group:
ecom_order_discount
3. GOLD member: 10% off
3. GOLD member: 10% off
- When:
loyaltyTier = "GOLD" - Then:
purchaseSubtotalUsd -= 10%(rounded to 2 decimal places, HALF_UP) - Mutex group:
ecom_order_discount
4. SILVER member: 5% off
4. SILVER member: 5% off
- When:
loyaltyTier = "SILVER" - Then:
purchaseSubtotalUsd -= 5%(rounded to 2 decimal places, HALF_UP) - Mutex group:
ecom_order_discount
5. Free shipping: members or USD 35+
5. Free shipping: members or USD 35+
- When:
loyaltyTier in ["BRONZE", "SILVER", "GOLD", "PLATINUM"]ORpurchaseSubtotalUsd ≥ 35 - Then:
freeShipping = true
6. Member rewards: 5% back
6. Member rewards: 5% back
- When:
loyaltyTier in ["BRONZE", "SILVER", "GOLD", "PLATINUM"] - Then:
loyaltyCreditUsd += 5% × purchaseSubtotalUsd(rounded to 2 decimal places, HALF_UP)
7. AI offer cap: 5% on electronics
7. AI offer cap: 5% on electronics
- When:
aiSuggestedDiscountPercent > 5ANDcartCategoryTags has any of ["electronics"] - Then:
aiSuggestedDiscountPercent = 5 - Mutex group:
ecom_ai_offer_cap
8. AI offer cap: 10% under USD 1,000 lifetime spend
8. AI offer cap: 10% under USD 1,000 lifetime spend
- When:
aiSuggestedDiscountPercent > 10ANDcustomerLtvUsd < 1000 - Then:
aiSuggestedDiscountPercent = 10 - Mutex group:
ecom_ai_offer_cap
9. AI offer ceiling: 15%
9. AI offer ceiling: 15%
- When:
aiSuggestedDiscountPercent > 15 - Then:
aiSuggestedDiscountPercent = 15 - Mutex group:
ecom_ai_offer_cap
10. Flag AI offers above 30% for review
10. Flag AI offers above 30% for review
- When:
aiSuggestedDiscountPercent > 30 - Then:
aiOfferReviewRequired = true
Samples
Guest’s first order with WELCOME15
WELCOME15 takes 15% off the USD 64 subtotal. The free-shipping rule checks the USD 64 in the request, not the discounted USD 54.40. The code’s USD 50 minimum keeps both above USD 35. Fired: WELCOME15: 15% off first order (USD 50+), Free shipping: members or USD 35+PLATINUM member, AI proposes 25% off
Actions run in priority order, and each one works on the values the earlier ones changed. The reward is 5% of the discounted USD 204.00. The AI offer is cut to the 15% ceiling. Fired: PLATINUM member: 15% off, Free shipping: members or USD 35+, Member rewards: 5% back, AI offer ceiling: 15%GOLD repeat order with electronics, AI proposes 60% off
The strictest cap, 5% for electronics, wins. The other two caps lose and stay in the decision traces with status Blocked. Conditions read only the request, so the review flag sees the AI’s original 60%, not the capped 5%. Fired: GOLD member: 10% off, Free shipping: members or USD 35+, Member rewards: 5% back, AI offer cap: 5% on electronics, Flag AI offers above 30% for review Blocked (matched, but lost to a higher-priority rule): AI offer cap: 10% under USD 1,000 lifetime spend, AI offer ceiling: 15%Fintech: Transfer Approval
Risk-score bands, a review of transfers over USD 10,000, limits for new and unverified accounts, velocity checks, and limits on transfers an AI agent starts. Applying it creates the policy group Fintech Transfer Risk & Limits with a draft version.Facts
Send every input fact on each request, using a neutral value when one does not apply. The rules write the output facts, so do not send those. Input factsUSER, AI_AGENT, SCHEDULEDRules
1. Decline: risk score 75+
1. Decline: risk score 75+
- When:
paymentRiskScore ≥ 75 - Then:
transferDecision = "DECLINE",BLOCK RISK_SCORE_HIGHEST - Mutex group:
fin_transfer_decision
2. Decline: unverified over USD 300 in 7 days
2. Decline: unverified over USD 300 in 7 days
- When:
isIdentityVerified = falseANDweeklyOutflowUsd > 300 - Then:
transferDecision = "DECLINE",BLOCK UNVERIFIED_WEEKLY_LIMIT - Mutex group:
fin_transfer_decision
3. Decline: AI-initiated transfer over USD 1,000
3. Decline: AI-initiated transfer over USD 1,000
- When:
initiatorType = "AI_AGENT"ANDtransferAmountUsd > 1000 - Then:
transferDecision = "DECLINE",BLOCK AI_TRANSFER_OVER_LIMIT - Mutex group:
fin_transfer_decision
4. Review: risk score 65+
4. Review: risk score 65+
- When:
paymentRiskScore ≥ 65 - Then:
transferDecision = "REVIEW",BLOCK RISK_SCORE_ELEVATED - Mutex group:
fin_transfer_decision
5. Review: transfer over USD 10,000
5. Review: transfer over USD 10,000
- When:
transferAmountUsd > 10000 - Then:
transferDecision = "REVIEW",BLOCK HIGH_VALUE_TRANSFER - Mutex group:
fin_transfer_decision
6. Review: account under 30 days, over USD 500 per transfer or USD 1,000 in 7 days
6. Review: account under 30 days, over USD 500 per transfer or USD 1,000 in 7 days
- When:
accountAgeDays < 30AND (transferAmountUsd > 500ORweeklyOutflowUsd > 1000) - Then:
transferDecision = "REVIEW",BLOCK NEW_ACCOUNT_OUTFLOW - Mutex group:
fin_transfer_decision
7. Review: 10+ transfers in 24h
7. Review: 10+ transfers in 24h
- When:
transfersLast24hCount ≥ 10 - Then:
transferDecision = "REVIEW",BLOCK VELOCITY_24H - Mutex group:
fin_transfer_decision
8. Step-up: AI-initiated over USD 100 or to a new payee
8. Step-up: AI-initiated over USD 100 or to a new payee
- When:
initiatorType = "AI_AGENT"AND (transferAmountUsd > 100ORisNewPayee = true) AND (transferAmountUsd ≥ 0ANDweeklyOutflowUsd ≥ 0ANDaccountAgeDays ≥ 0AND (isIdentityVerified = trueORisIdentityVerified = false) ANDpaymentRiskScore ≥ 0ANDtransfersLast24hCount ≥ 1AND (isNewPayee = trueORisNewPayee = false) ANDinitiatorType in ["USER", "AI_AGENT", "SCHEDULED"]) - Then:
transferDecision = "STEP_UP",BLOCK AI_TRANSFER_CONFIRMATION - Mutex group:
fin_transfer_decision
9. Step-up: new payee over USD 200
9. Step-up: new payee over USD 200
- When:
isNewPayee = trueANDtransferAmountUsd > 200AND (transferAmountUsd ≥ 0ANDweeklyOutflowUsd ≥ 0ANDaccountAgeDays ≥ 0AND (isIdentityVerified = trueORisIdentityVerified = false) ANDpaymentRiskScore ≥ 0ANDtransfersLast24hCount ≥ 1AND (isNewPayee = trueORisNewPayee = false) ANDinitiatorType in ["USER", "AI_AGENT", "SCHEDULED"]) - Then:
transferDecision = "STEP_UP",BLOCK NEW_PAYEE_STEP_UP - Mutex group:
fin_transfer_decision
10. Approve: every input present, no risk rule matched
10. Approve: every input present, no risk rule matched
- When:
transferAmountUsd ≥ 0ANDweeklyOutflowUsd ≥ 0ANDaccountAgeDays ≥ 0AND (isIdentityVerified = trueORisIdentityVerified = false) ANDpaymentRiskScore ≥ 0ANDtransfersLast24hCount ≥ 1AND (isNewPayee = trueORisNewPayee = false) ANDinitiatorType in ["USER", "AI_AGENT", "SCHEDULED"] - Then:
transferDecision = "APPROVE" - Mutex group:
fin_transfer_decision
11. Review: default hold
11. Review: default hold
- When: Catch-all
- Then:
transferDecision = "REVIEW",BLOCK INPUT_MISSING - Mutex group:
fin_transfer_decision
Samples
Routine transfer
No risk rule matches and every input has a value, so the default approval wins. The approval still shows up by rule name in the decision traces. Fired: Approve: every input present, no risk rule matched Blocked (matched, but lost to a higher-priority rule): Review: default holdRisk model returns no score
The risk model failed, so paymentRiskScore is null. No condition matches null, and the default approval needs every input, so the default hold wins: REVIEW with blockReason INPUT_MISSING. Hold the transfer until a person reviews it. Fired: Review: default holdAI agent sends USD 85 to a new payee
The amount is small, but an AI agent paying a new payee needs the account holder’s confirmation. The response sets isBlocked to true with blockReason AI_TRANSFER_CONFIRMATION. Send the transfer only after the account holder confirms. Fired: Step-up: AI-initiated over USD 100 or to a new payee Blocked (matched, but lost to a higher-priority rule): Approve: every input present, no risk rule matched, Review: default holdAI agent sends USD 1,800 from a new account
Seven rules match. The response carries one decision, DECLINE, with its blockReason. The four other risk rules, the default approval, and the default hold lose to it and stay in the decision traces with status Blocked. Fired: Decline: AI-initiated transfer over USD 1,000 Blocked (matched, but lost to a higher-priority rule): Review: risk score 65+, Review: account under 30 days, over USD 500 per transfer or USD 1,000 in 7 days, Step-up: AI-initiated over USD 100 or to a new payee, Step-up: new payee over USD 200, Approve: every input present, no risk rule matched, Review: default holdSaaS: Plan Limits
Seat and usage limits by plan, feature gating, trial usage caps, usage overage charges, and a cap on credits an AI support agent proposes. Applying it creates the policy group SaaS Plan Limits & Credits with a draft version.Facts
Send every input fact on each request, using a neutral value when one does not apply. The rules write the output facts, so do not send those. Input factsFREE, TEAM, BUSINESS, ENTERPRISESSO, AUDIT_LOG, NONERules
1. Block: SSO and audit log need BUSINESS or above
1. Block: SSO and audit log need BUSINESS or above
- When:
requestedFeature in ["SSO", "AUDIT_LOG"]ANDplanTier in ["FREE", "TEAM"] - Then:
BLOCK FEATURE_NOT_IN_PLAN - Mutex group:
saas_entitlement_block
2. Block: FREE plan over 10 seats
2. Block: FREE plan over 10 seats
- When:
planTier = "FREE"ANDseatCount > 10 - Then:
BLOCK SEAT_LIMIT_REACHED - Mutex group:
saas_entitlement_block
3. Block: FREE plan over 10,000 API calls
3. Block: FREE plan over 10,000 API calls
- When:
planTier = "FREE"ANDmonthlyApiCalls > 10000 - Then:
BLOCK USAGE_LIMIT_REACHED - Mutex group:
saas_entitlement_block
4. Block: trial over 10,000 API calls
4. Block: trial over 10,000 API calls
- When:
isTrial = trueANDmonthlyApiCalls > 10000 - Then:
BLOCK TRIAL_USAGE_LIMIT - Mutex group:
saas_entitlement_block
5. Block: TEAM plan over 300,000 API calls
5. Block: TEAM plan over 300,000 API calls
- When:
planTier = "TEAM"ANDmonthlyApiCalls > 300000 - Then:
BLOCK USAGE_HARD_CAP - Mutex group:
saas_entitlement_block
6. TEAM overage: USD 1 per 1,000 calls over 100,000
6. TEAM overage: USD 1 per 1,000 calls over 100,000
- When:
planTier = "TEAM"ANDisTrial = falseANDmonthlyApiCalls > 100000ANDmonthlyApiCalls ≤ 300000 - Then:
overageChargeUsd = 0.1% × monthlyApiCalls(rounded to 2 decimal places, HALF_UP),overageChargeUsd -= 100
7. TEAM overage at the hard cap: USD 200
7. TEAM overage at the hard cap: USD 200
- When:
planTier = "TEAM"ANDisTrial = falseANDmonthlyApiCalls > 300000 - Then:
overageChargeUsd = 200
8. AI credit: none on FREE plans or trials
8. AI credit: none on FREE plans or trials
- When: (
planTier = "FREE"ORisTrial = true) ANDaiGrantedCreditUsd > 0 - Then:
aiGrantedCreditUsd = 0,creditApprovalRequired = true - Mutex group:
saas_credit_cap
9. AI credit cap: USD 100 per grant
9. AI credit cap: USD 100 per grant
- When: (
planTier in ["TEAM", "BUSINESS", "ENTERPRISE"]ANDisTrial = false) ANDaiGrantedCreditUsd > 100 - Then:
aiGrantedCreditUsd = 100,creditApprovalRequired = true - Mutex group:
saas_credit_cap
10. AI credit: paid plans get it as proposed, up to the cap
10. AI credit: paid plans get it as proposed, up to the cap
- When: (
planTier in ["TEAM", "BUSINESS", "ENTERPRISE"]ANDisTrial = false) ANDaiGrantedCreditUsd > 0 - Then:
creditApprovalRequired = false - Mutex group:
saas_credit_cap
11. AI credit: default hold
11. AI credit: default hold
- When:
aiGrantedCreditUsd > 0 - Then:
aiGrantedCreditUsd = 0,creditApprovalRequired = true - Mutex group:
saas_credit_cap
Samples
TEAM workspace over its included usage
Two actions in one rule run in order: 135,000 calls × USD 0.001 = USD 135.00, minus the included USD 100, leaves USD 35.00. Fired: TEAM overage: USD 1 per 1,000 calls over 100,000FREE workspace adds an 11th seat
Both the seat limit and the usage limit match. Only the seat limit’s blockReason goes out. The usage limit loses to the seat limit and stays in the decision traces with status Blocked. Fired: Block: FREE plan over 10 seats Blocked (matched, but lost to a higher-priority rule): Block: FREE plan over 10,000 API callsAI support agent offers a USD 250 credit
The credit is cut to USD 100. The response records the cut in aiGrantedCreditUsd__delta as -150, and a person approves that USD 150. Fired: AI credit cap: USD 100 per grant Blocked (matched, but lost to a higher-priority rule): AI credit: paid plans get it as proposed, up to the cap, AI credit: default holdUSD 80 credit offer when the plan is unknown
planTier is null, so no plan rule matches and the credit is not granted as proposed. The default hold sets it to 0 and turns on creditApprovalRequired, so a person decides. The plan limits do not match null either, so never send planTier as null. Fired: AI credit: default holdInsurance: Claim Triage
Personal auto claims. Small claims with no flag are fast-tracked. Theft, losses in a policy’s first 30 days, injuries, and large or low-confidence AI estimates go to an adjuster. Fraud signals go to special investigation. Applying it creates the policy group Insurance Claim Triage with a draft version.Facts
Send every input fact on each request, using a neutral value when one does not apply. The rules write the output facts, so do not send those. Input factsGLASS, COLLISION, COMPREHENSIVE, THEFTRules
1. Investigate: fraud score 80+
1. Investigate: fraud score 80+
- When:
claimFraudScore ≥ 80 - Then:
claimRoute = "SPECIAL_INVESTIGATION",BLOCK SIU_REFERRAL_FRAUD_SCORE - Mutex group:
ins_claim_route
2. Investigate: theft on a policy under 30 days old
2. Investigate: theft on a policy under 30 days old
- When:
claimType = "THEFT"ANDpolicyAgeDays < 30 - Then:
claimRoute = "SPECIAL_INVESTIGATION",BLOCK SIU_REFERRAL_EARLY_THEFT - Mutex group:
ins_claim_route
3. Adjuster: injury reported
3. Adjuster: injury reported
- When:
hasInjury = true - Then:
claimRoute = "ADJUSTER_REVIEW",BLOCK INJURY_REPORTED - Mutex group:
ins_claim_route
4. Adjuster: theft claim
4. Adjuster: theft claim
- When:
claimType = "THEFT" - Then:
claimRoute = "ADJUSTER_REVIEW",BLOCK THEFT_CLAIM - Mutex group:
ins_claim_route
5. Adjuster: loss in the policy's first 30 days
5. Adjuster: loss in the policy's first 30 days
- When:
policyAgeDays < 30 - Then:
claimRoute = "ADJUSTER_REVIEW",BLOCK EARLY_LOSS - Mutex group:
ins_claim_route
6. Adjuster: AI glass payout over USD 1,000
6. Adjuster: AI glass payout over USD 1,000
- When:
claimType = "GLASS"ANDaiEstimatedPayoutUsd > 1000 - Then:
claimRoute = "ADJUSTER_REVIEW",BLOCK GLASS_PAYOUT_OVER_LIMIT - Mutex group:
ins_claim_route
7. Adjuster: AI payout over USD 2,500
7. Adjuster: AI payout over USD 2,500
- When:
aiEstimatedPayoutUsd > 2500 - Then:
claimRoute = "ADJUSTER_REVIEW",BLOCK PAYOUT_OVER_FAST_TRACK_LIMIT - Mutex group:
ins_claim_route
8. Adjuster: AI confidence below 0.8
8. Adjuster: AI confidence below 0.8
- When:
aiEstimateConfidence < 0.8 - Then:
claimRoute = "ADJUSTER_REVIEW",BLOCK LOW_ESTIMATE_CONFIDENCE - Mutex group:
ins_claim_route
9. Adjuster: 2+ prior claims in 3 years
9. Adjuster: 2+ prior claims in 3 years
- When:
priorClaimsCount ≥ 2 - Then:
claimRoute = "ADJUSTER_REVIEW",BLOCK FREQUENT_CLAIMANT - Mutex group:
ins_claim_route
10. Fast-track: every input present, no flag raised
10. Fast-track: every input present, no flag raised
- When:
claimType in ["GLASS", "COLLISION", "COMPREHENSIVE", "THEFT"]ANDaiEstimatedPayoutUsd ≥ 0ANDaiEstimateConfidence ≥ 0ANDpolicyAgeDays ≥ 0ANDpriorClaimsCount ≥ 0AND (hasInjury = trueORhasInjury = false) ANDclaimFraudScore ≥ 0 - Then:
claimRoute = "FAST_TRACK" - Mutex group:
ins_claim_route
11. Adjuster: default hold
11. Adjuster: default hold
- When: Catch-all
- Then:
claimRoute = "ADJUSTER_REVIEW",BLOCK INPUT_MISSING - Mutex group:
ins_claim_route
Samples
Small windshield claim
No flag is raised and every input has a value, so the claim is fast-tracked. Fired: Fast-track: every input present, no flag raised Blocked (matched, but lost to a higher-priority rule): Adjuster: default holdWindshield claim without an estimate confidence
The estimate model returned no confidence, so aiEstimateConfidence is null. The confidence rule does not match null, and fast-track needs every input, so the default hold wins: ADJUSTER_REVIEW with blockReason INPUT_MISSING. Do not pay until an adjuster reviews it. Fired: Adjuster: default holdCollision with a USD 6,800 AI estimate
Confidence is high, but the payout is above the USD 2,500 fast-track ceiling, so an adjuster reviews it. The response sets isBlocked to true. Do not pay until the review is done. Fired: Adjuster: AI payout over USD 2,500 Blocked (matched, but lost to a higher-priority rule): Fast-track: every input present, no flag raised, Adjuster: default holdTheft 12 days after policy start, fraud score 86
Special investigation wins, so claimRoute is SPECIAL_INVESTIGATION and isBlocked is true. The early-theft, theft, early-loss, payout, and confidence flags also match and stay in the decision traces for the investigator. Fired: Investigate: fraud score 80+ Blocked (matched, but lost to a higher-priority rule): Investigate: theft on a policy under 30 days old, Adjuster: theft claim, Adjuster: loss in the policy’s first 30 days, Adjuster: AI payout over USD 2,500, Adjuster: AI confidence below 0.8, Fast-track: every input present, no flag raised, Adjuster: default holdAI Agent: Action Approval
Example rules for actions an AI agent proposes: an allowlist of action types, personal-data checks, per-action and daily amount limits, human approval for refunds and purchases, and a confidence threshold. Applying it creates the policy group AI Agent Action Approval with a draft version.Facts
Send every input fact on each request, using a neutral value when one does not apply. The rules write the output facts, so do not send those. Input factsRules
1. Deny: action type not on the allowlist
1. Deny: action type not on the allowlist
- When:
agentActionType not in ["ISSUE_REFUND", "APPLY_CREDIT", "PURCHASE", "SEND_MESSAGE", "UPDATE_TICKET"] - Then:
agentDecision = "DENY",BLOCK ACTION_NOT_ALLOWED_FOR_AGENT - Mutex group:
agent_action_decision
2. Deny: personal data to a third party
2. Deny: personal data to a third party
- When:
containsPii = trueANDisThirdPartyRecipient = true - Then:
agentDecision = "DENY",BLOCK PII_TO_THIRD_PARTY - Mutex group:
agent_action_decision
3. Deny: single action over USD 1,000
3. Deny: single action over USD 1,000
- When:
actionAmountUsd > 1000 - Then:
agentDecision = "DENY",BLOCK AMOUNT_OVER_HARD_LIMIT - Mutex group:
agent_action_decision
4. Needs approval: over USD 500 per customer in 24 hours
4. Needs approval: over USD 500 per customer in 24 hours
- When:
dailyAgentAmountUsd > 500ANDactionAmountUsd > 0 - Then:
agentDecision = "NEEDS_APPROVAL",BLOCK DAILY_AMOUNT_LIMIT - Mutex group:
agent_action_decision
5. Needs approval: refunds or purchases over USD 100
5. Needs approval: refunds or purchases over USD 100
- When:
agentActionType in ["ISSUE_REFUND", "PURCHASE"]ANDactionAmountUsd > 100 - Then:
agentDecision = "NEEDS_APPROVAL",BLOCK AMOUNT_NEEDS_APPROVAL - Mutex group:
agent_action_decision
6. Needs approval: confidence below 0.7
6. Needs approval: confidence below 0.7
- When:
checkerConfidence < 0.7 - Then:
agentDecision = "NEEDS_APPROVAL",BLOCK LOW_CONFIDENCE - Mutex group:
agent_action_decision
7. Allow: goodwill credit capped at USD 50
7. Allow: goodwill credit capped at USD 50
- When:
agentActionType = "APPLY_CREDIT"ANDactionAmountUsd > 50AND (actionAmountUsd ≥ 0ANDdailyAgentAmountUsd ≥ 0ANDcheckerConfidence ≥ 0AND (containsPii = trueORcontainsPii = false) AND (isThirdPartyRecipient = trueORisThirdPartyRecipient = false)) - Then:
actionAmountUsd = 50,agentDecision = "ALLOW" - Mutex group:
agent_action_decision
8. Allow: allowlisted action, every input present, no other rule matched
8. Allow: allowlisted action, every input present, no other rule matched
- When:
agentActionType in ["ISSUE_REFUND", "APPLY_CREDIT", "PURCHASE", "SEND_MESSAGE", "UPDATE_TICKET"]AND (actionAmountUsd ≥ 0ANDdailyAgentAmountUsd ≥ 0ANDcheckerConfidence ≥ 0AND (containsPii = trueORcontainsPii = false) AND (isThirdPartyRecipient = trueORisThirdPartyRecipient = false)) - Then:
agentDecision = "ALLOW" - Mutex group:
agent_action_decision
9. Needs approval: default hold for allowlisted actions
9. Needs approval: default hold for allowlisted actions
- When:
agentActionType in ["ISSUE_REFUND", "APPLY_CREDIT", "PURCHASE", "SEND_MESSAGE", "UPDATE_TICKET"] - Then:
agentDecision = "NEEDS_APPROVAL",BLOCK INPUT_MISSING - Mutex group:
agent_action_decision
10. Deny: no rule above matched
10. Deny: no rule above matched
- When: Catch-all
- Then:
agentDecision = "DENY",BLOCK ACTION_NOT_ALLOWED_FOR_AGENT - Mutex group:
agent_action_decision
Samples
USD 45 refund
The action is within every limit and every input has a value, so it is allowed. Fired: Allow: allowlisted action, every input present, no other rule matched Blocked (matched, but lost to a higher-priority rule): Needs approval: default hold for allowlisted actions, Deny: no rule above matchedUSD 45 refund while the checker model is down
The checker model returned no score, so checkerConfidence is null. The confidence rule does not match null, and both allow rules need every input, so the default hold wins: NEEDS_APPROVAL with blockReason INPUT_MISSING. Do not run the refund until a person approves it. Fired: Needs approval: default hold for allowlisted actions Blocked (matched, but lost to a higher-priority rule): Deny: no rule above matchedUSD 180 refund
Refunds over USD 100 wait for a person’s approval. The response sets isBlocked to true. Do not run the refund until someone approves it. Fired: Needs approval: refunds or purchases over USD 100 Blocked (matched, but lost to a higher-priority rule): Allow: allowlisted action, every input present, no other rule matched, Needs approval: default hold for allowlisted actions, Deny: no rule above matchedAgent in a manipulated chat offers a USD 1,500 credit
The checker model scored the action 0.95, and the per-action limit still denies it. The other matching rules, including the daily limit and the credit cap, lose to the per-action limit and stay in the decision traces with status Blocked. The amount stays at USD 1,500. Fired: Deny: single action over USD 1,000 Blocked (matched, but lost to a higher-priority rule): Needs approval: over USD 500 per customer in 24 hours, Allow: goodwill credit capped at USD 50, Allow: allowlisted action, every input present, no other rule matched, Needs approval: default hold for allowlisted actions, Deny: no rule above matchedUSD 80 goodwill credit
No deny or approval rule matches, so the credit cap wins. The amount is cut to USD 50 and the action is allowed. Fired: Allow: goodwill credit capped at USD 50 Blocked (matched, but lost to a higher-priority rule): Allow: allowlisted action, every input present, no other rule matched, Needs approval: default hold for allowlisted actions, Deny: no rule above matchedAgent calls a tool not on the allowlist
EXPORT_DATA is not on the allowlist, so the action is denied with blockReason ACTION_NOT_ALLOWED_FOR_AGENT. A new tool the agent gains gets the same answer until you add it to the lists in action_not_allowlisted and default_allow. Add it to default_approval too, or a call for that tool with a null input is denied instead of waiting for approval. Fired: Deny: action type not on the allowlist Blocked (matched, but lost to a higher-priority rule): Deny: no rule above matchedApplying a Template
- Go to Settings → Domain Templates.
- Click Preview on a template card to inspect the facts and rules before committing. If one of the template’s keys already exists in your tenant with a different definition, the preview lists it, and the template cannot be applied until you delete that fact or change it to match.
- Click Apply to create the policy group.
- Optionally provide a custom group name. If left blank, a default name is generated (with a date suffix if the name already exists).
What Happens on Apply
P-052, for example loyaltyTier: "Gold" instead of "GOLD". Without the allowed values, the rule that checks for "GOLD" would quietly not match. You can widen or remove the allowed values in Fact Definitions.Customizing After Apply
Templates are starting points. After applying, you can freely:- Edit any rule (condition, action, priority, mutex).
- Add or remove rules in the version.
- Delete facts you don’t need once no rule references them. Rules in deleted groups don’t count, and the facts have no special protection.
- Rename the policy group.
- Adjust the version’s effective dates before publishing.
FAQ
Can I apply the same template twice? Yes. Each apply creates a new policy group, and the facts from the first apply are reused, not duplicated. If you have since changed the type or allowed values of one of them, the second apply fails withP-061 until it matches the template again. If the default group name is taken, a date suffix is appended automatically.
What if my tenant already has a fact with the same key?
If it has the same definition, apply keeps it as it is. The definition differs when the type differs, or, for an input fact, when the allowed values or range differ. Then the preview lists the key, the Console disables Apply, and the apply endpoint fails with P-061 without creating anything. Delete that fact or change it to match the template, then apply. A fact that rules use cannot be deleted or retyped (FD-006, FD-007), but you can change its allowed values or range. Policies you have already published pick up the change when you publish them again.
Can I delete a template’s facts later?
Yes, once no rule references them. Rules in a deleted group don’t count. Template-applied facts are regular tenant facts with no special protection, and the same guard applies: a fact that rules reference cannot be deleted (FD-006) or retyped (FD-007). The error reports how many rules reference it. Remove those rules, or edit them to stop using the fact, and the delete goes through. See Managing Facts.
Can I roll back an apply?
Not as a single operation. To undo, delete the policy group the template created, then delete the facts you don’t need. If you deployed the group, undeploy it first. A deleted group’s rules no longer block deleting a fact, but a fact that another group’s rules use stays blocked. A group that was never executed, deployed, or replayed is permanently deleted 30 days after you delete it, together with its application history; otherwise the history stays for audit.

