Ads and Commerce

Rules best practices

Updated: Aug 12, 2026
Copy for LLM
Ads MCP server rules limit what an AI agent can do on one of your assets. A rule denies a specific agent action on a specific ad account or product catalog — for example, deny any budget increase above 20%, or deny delivery status changes.
Rules are the same controls shown on the ads MCP server page in Meta Business Suite settings. This API is the programmatic surface for them, which matters when you manage many assets and cannot configure each one by hand.
Ads MCP server rules are in limited availability. If your business is not enrolled, the ad account endpoint returns error code 10 and the catalog endpoint returns HTTP 403.

Endpoints

Both endpoints share one rule model, so you learn it once and apply it to either asset type. Prepend every path with https://ads-api.facebook.com/v25.0.
AssetMethodsPath
Ad account
GET, POST
/marketing-api/businesses/<BUSINESS_ID>/accounts/act_<AD_ACCOUNT_ID>/ads_mcp_rules
Catalog
GET, POST
/catalog/businesses/<BUSINESS_ID>/product_catalogs/<CATALOG_ID>/ads_mcp_rules
Call ads-api.facebook.com, not graph.facebook.com. Use version v25.0 — v22.0 is deprecated and auto-upgrades.

Permissions

EndpointRead (GET)Write (POST)
Ad account
ads_read, ads_management, or business_management
ads_management or business_management
Catalog
catalog_management, ads_read, or ads_management
catalog_management or ads_management
A business_management-only token works on the ad account endpoint but returns HTTP 401 on the catalog endpoint. Request catalog_management or ads_management for catalog work.
Both endpoints accept system user tokens. Prefer a system user for automation: it is not tied to a person who can leave the business or lose access, which is what you want for a scheduled job that audits or reapplies rules.

The rule model

FieldDescription
id
Rule ID. Informational — there is no per-ID GET, PUT, or DELETE.
action
The agent action the rule governs.
trigger_type
When the rule fires.
status
active (enforced) or paused (configured, not enforced).
business_id
The business the rule is scoped to. Server-set from the path.
metadata
Ad account only. The budget trigger’s parameters; empty for the always trigger.

Actions and triggers by asset

Each endpoint accepts only its own asset’s actions. A read may also return other stored actions.
Assetactiontrigger_typemetadataWhat the rule denies
Ad account
create_campaign
always
none
Creating campaigns
Ad account
create_ad_set
always
none
Creating ad sets
Ad account
create_ad
always
none
Creating ads
Ad account
edit_budget
percentage_change
max_percentage
Budget increases above a percentage
Ad account
edit_budget
absolute_change
max_amount_cents
Budget increases above an amount
Ad account
edit_budget
absolute_max
max_value_cents
Budgets above a ceiling
Ad account
edit_targeting
always
none
Targeting and audience changes
Ad account
edit_creative
always
none
Creative changes
Ad account
edit_status
always
none
Delivery status changes, such as pausing or activating
Ad account
all
always
none
Every agent action on the account
Catalog
all
always
none
Every agent action on the catalog
Catalog
edit_catalog_products
active_spend_gate
none
Product changes while the catalog is active in ads
Catalog
edit_catalog_product_sets
active_spend_gate
none
Product set changes while the catalog is active in ads
All three edit_budget triggers also accept an optional budget_dimension of daily, lifetime, or both. It defaults to both. Threshold values are integers, and the _cents values are in the ad account’s currency.
Send metadata as a JSON string inside a form POST. Nothing in the rule shape tells you which sub-fields a trigger expects, so match the table above — a wrong combination returns HTTP 400.

Write rules declaratively

A write sends one rule and returns the asset’s full resulting rule set, so you do not need a follow-up read to confirm the result.
curl -sS -X POST \
  "https://ads-api.facebook.com/v25.0/marketing-api/businesses/<BUSINESS_ID>/accounts/act_<AD_ACCOUNT_ID>/ads_mcp_rules" \
  -d "action=edit_budget" \
  -d "trigger_type=percentage_change" \
  -d "status=active" \
  -d 'metadata={"max_percentage":20,"budget_dimension":"both"}' \
  -d "access_token=<ACCESS_TOKEN>"
Writes are keyed on the (action, trigger_type) pair. Posting the same pair again updates the existing rule instead of creating a duplicate, which makes it safe to reapply your intended configuration on a schedule without first reading current state or tracking rule IDs.

Turning a rule off differs by asset

There is no DELETE verb. To turn a rule off, post it again with status=paused — but the two assets treat that differently:
  • Ad account — the rule is kept and stops being enforced. A later read still returns it, with status of paused.
  • Catalog — the rule is removed. A later read does not return it at all.
If you reconcile against a desired-state configuration, do not treat a missing catalog rule as drift. On a catalog, absent and paused are the same state.

Plan for one call per rule per asset

There is no batch endpoint. Configuring several rules across several assets means one call per rule, per asset. When you fan out across many assets:
  • Watch the x-business-use-case-usage response header and back off as you approach the limit.
  • Reapply only what changed. Because writes are idempotent, a reconcile loop can read once per asset and write only the differences.

Handle both error formats

The two endpoints return different error shapes, so a client that reads one format will silently fail to parse the other:
  • Ad account — Graph-style errors: {"error":{"message":"...","code":...}}
  • Catalog — problem details, as in RFC 7807: {"title":"...","detail":"...","status":...}

Next steps

  • Overview — What the ads MCP server is and what it can do
  • Get started — Requirements, authentication, and how to connect an AI agent