{
  "question": "How do I restrict an AI agent to an allowlist of merchant domains and categories?",
  "slug": "how-to-restrict-an-ai-agent-to-an-allowlist-of-merchant-domains-and-categories",
  "url": "https://www.rightshold.com/answers/how-to-restrict-an-ai-agent-to-an-allowlist-of-merchant-domains-and-categories",
  "short_answer": "A spend cap limits how much an agent can spend. An allowlist limits where it can spend. Put both on the agent's credential with set_spend_policy: allowed_domains (exact domains, or *.example.com to include subdomains) and allowed_categories (short labels such as data_api or cloud_compute). Every proposed purchase then goes through authorize_spend. A merchant that isn't on the list gets a signed deny with merchant_not_allowed. A category that isn't on the list, or a purchase sent with no category, gets category_not_allowed. The per-purchase and daily caps still apply on top, so an allowlisted merchant can still be denied with over_per_transaction_cap or over_daily_cap. An empty list means no restriction, so set both lists on purpose. This page is about the merchant allowlist itself. Card MCC controls, cap-only policies and mid-task revoke are covered on separate pages. Merchants check the allow receipt free with verify_spend_authorization, and ledger_verify keeps every policy version and decision checkable.",
  "checklist": [
    "List the merchants the agent really needs (API vendors, cloud providers, one marketplace) and the kinds of purchase it makes. Start narrow. It is easier to add a domain after a deny than to explain a purchase you never meant to allow.",
    "Write allowed_domains as exact hostnames (api.example.com) or wildcards (*.example.com, which also matches example.com). Rightshold lowercases entries, strips a leading www. and the scheme, and accepts up to 100 domains.",
    "Write allowed_categories as your own short labels (data_api, cloud_compute, saas_seat), up to 100. The agent must send the same label as category on every authorize_spend call. If categories are set and the category is missing or not on the list, the answer is category_not_allowed.",
    "Remember that an empty allowed_domains or allowed_categories list means no restriction for that field. Setting both lists is what turns the allowlist on.",
    "Keep caps on top: currency, per_tx_max_minor and daily_max_minor are still checked for allowlisted merchants. set_spend_policy needs at least one cap, so an allowlist can't be used as an unlimited pass.",
    "Make authorize_spend the step before every payment and pass the real merchant_domain. A signed deny lists every failing reason at once (for example merchant_not_allowed and over_daily_cap), so the agent and the owner can see exactly what to fix.",
    "Have merchants (or your own payment step) check the allow receipt with verify_spend_authorization and accept it only before valid_until (15 minutes). On card rails, mirror the same list with Stripe Issuing allowed_categories (merchant category codes) so both layers agree.",
    "Change the list only by recording a new policy version. Add a domain through a human approval if it widens spend, and test it: a listed domain allows, an unlisted one returns merchant_not_allowed, and a wrong category returns category_not_allowed."
  ],
  "sections": [
    {
      "heading": "Allowlists limit where an agent spends; caps limit how much",
      "points": [
        "A per-purchase or daily cap still lets the agent pay any merchant until the money runs out. A prompt-injected or confused agent can stay under the cap and still send money to a site you never chose. An allowlist turns this around: every merchant and category is denied unless you named it.",
        "Pages on per-request and per-run caps, task-scoped spend policies and virtual cards with spending limits cover how much an agent can spend. This page covers where it can spend. The two layers stack: a purchase must pass both.",
        "NIST SP 800-53 Rev. 5 AC-6 (least privilege) and CM-7(5) (authorized software: allow-by-exception) are the control language for this: allow only what the task needs, and deny everything else by default."
      ]
    },
    {
      "heading": "allowed_domains and allowed_categories in set_spend_policy",
      "points": [
        "set_spend_policy stores currency, per_tx_max_minor, daily_max_minor, allowed_domains, allowed_categories and an optional expires_at on the agent's credential. A new call records a new version that replaces the old one from the moment it is recorded, and old versions stay on the ledger.",
        "authorize_spend checks merchant_domain against allowed_domains. An exact match passes, and *.example.com matches example.com and any subdomain. Anything else adds merchant_not_allowed. It checks category against allowed_categories, and a missing or unlisted label adds category_not_allowed.",
        "The decision is plain code: the same inputs always give the same answer. It is signed and written to the spend_authorizations ledger stream, so an owner can later show that a deny was the policy working, not a bug."
      ]
    },
    {
      "heading": "Caps on top, card MCCs underneath, verified at checkout",
      "points": [
        "Caps still apply to allowlisted merchants. With a 10.00 per-purchase cap, a 25.00 order to an allowed domain returns over_per_transaction_cap, and the daily total still counts toward over_daily_cap.",
        "If the agent pays with a Stripe Issuing card, set spending_controls.allowed_categories (merchant category codes) on the card as a second layer. Stripe blocks every category that isn't on the list. Your Rightshold labels can be finer-grained than MCCs, so map each label to the MCCs it may use.",
        "Merchants or your checkout step verify the signed allow receipt free with verify_spend_authorization and accept it only before valid_until. ledger_verify is free and keyless for the chain of policy versions and decisions."
      ]
    }
  ],
  "checks": [],
  "ask_rightshold": {
    "start": "https://www.rightshold.com/start?ref=seo",
    "mcp_endpoint": "https://www.rightshold.com/mcp",
    "ask": "Restrict my purchasing agent to api.example.com and any subdomain of cloud.example.net, only for data_api and cloud_compute purchases, with a 10.00 USD per-purchase cap and 50.00 USD per day. Then tell me what authorize_spend returns for a merchant that isn't on the list.",
    "mcp_call": {
      "tool": "set_spend_policy",
      "arguments": {
        "credential_id": "crd_YOUR_AGENT_CREDENTIAL",
        "currency": "USD",
        "per_tx_max_minor": 1000,
        "daily_max_minor": 5000,
        "allowed_domains": [
          "api.example.com",
          "*.cloud.example.net"
        ],
        "allowed_categories": [
          "data_api",
          "cloud_compute"
        ]
      }
    },
    "also": [
      "Needs your owner account key. It's in the trust toolset (connect to /mcp?toolset=trust). Empty lists mean no restriction, so set both on purpose.",
      "authorize_spend returns a signed allow or deny with every failing reason: merchant_not_allowed, category_not_allowed, over_per_transaction_cap, over_daily_cap, policy_expired or credential_revoked.",
      "verify_spend_authorization is free. Merchants use it to check an allow receipt before valid_until.",
      "request_human_approval binds widening the allowlist to a human decision. ledger_verify is free and keyless for every policy version."
    ],
    "scope": "Rightshold records spending policies and signs allow/deny decisions on a hash-chained ledger. It never holds, moves or settles money. Making the agent call authorize_spend before paying, and making merchants or card controls refuse what was denied, are steps you run around those records. Category labels are yours to define and are not card-network MCCs. Not financial or legal advice."
  },
  "sources": [
    {
      "title": "NIST SP 800-53 Rev. 5: AC-6 (least privilege) and CM-7 (least functionality)",
      "url": "https://csrc.nist.gov/publications/detail/sp/800-53/rev-5/final"
    },
    {
      "title": "Stripe Issuing: spending controls (allowed_categories, blocked_categories, spending_limits)",
      "url": "https://docs.stripe.com/issuing/controls/spending-controls"
    },
    {
      "title": "Stripe Issuing: merchant categories",
      "url": "https://docs.stripe.com/issuing/categories"
    },
    {
      "title": "EU AI Act, Regulation (EU) 2024/1689: Article 14 (human oversight)",
      "url": "https://eur-lex.europa.eu/eli/reg/2024/1689/oj"
    },
    {
      "title": "RFC 6962: Certificate Transparency (append-only Merkle hash logs)",
      "url": "https://www.rfc-editor.org/rfc/rfc6962"
    },
    {
      "title": "Agent spending policies on Rightshold",
      "url": "https://www.rightshold.com/agent-spending-policies"
    }
  ],
  "related": [
    {
      "title": "How to give an AI agent a virtual card with a spending limit",
      "url": "https://www.rightshold.com/answers/how-to-give-an-ai-agent-a-virtual-card-with-a-spending-limit"
    },
    {
      "title": "How to set per-request and per-run spend caps for x402 agent payments",
      "url": "https://www.rightshold.com/answers/how-to-set-per-request-and-per-run-spend-caps-for-x402-agent-payments"
    },
    {
      "title": "How to give each AI agent a task-scoped spend policy with auto-expiring approvals",
      "url": "https://www.rightshold.com/answers/how-to-give-each-ai-agent-a-task-scoped-spend-policy-with-auto-expiring-approvals"
    },
    {
      "title": "How to enforce AI agent payment caps at the execution boundary, not in the prompt",
      "url": "https://www.rightshold.com/answers/how-to-enforce-ai-agent-payment-caps-at-the-execution-boundary-not-in-the-prompt"
    }
  ],
  "computed_from": "Curated guidance; license verdicts computed from Rightshold's license profiles at render time. Not legal advice.",
  "updated": "2026-11-07"
}