---
title: "What a draft rule would match, without saving it"
method: POST
path: "/projects/{project_id}/policy-rule-preview"
tags: ["Policy"]
---

# What a draft rule would match, without saving it

`POST /projects/{project_id}/policy-rule-preview`

## Request

- Base URL: `https://adslighthouse.com/api/v1`
- URL: `https://adslighthouse.com/api/v1/projects/{project_id}/policy-rule-preview`
- Auth: HTTP bearer

Evaluates a draft rule against the project's saved checks over a date range (last 30 days by default, at most 92 days) and returns how many ads, advertisers and cases it would match, with up to 20 recent examples. Use this to check whether the rule is scoped as intended before create_policy_rule; nothing is saved and no case is opened. No matches means none in the saved checks, not that none happened. Types and params: forbidden_terms {terms, fields: headline|description|display_url, applies_to, authorized_domains}; brand_term {extra_terms, authorized_domains}; direct_linking {authorized_domains}; promo_code {codes, any_explicit_code, allowed_codes, applies_to, authorized_domains}; position_limit {top_positions 1-10, applies_to, authorized_domains}; affiliate_id {authorized_ids}. applies_to is unauthorized (default for position limits) or all_non_owned (default for terms and codes). Your own domains never match, except for affiliate_id; advertisers classified as authorized retailers and authorized_domains count as authorized. A match is a lead to review: an observation shows an ad was displayed for a search at a moment, not proof of a violation, spend or a purchased keyword.

## Path parameters

- `project_id` string, required: The project: its id, its brand domain (for example nike.example) or its exact project or brand name. Unknown or ambiguous references return not_found; call list_projects then.

## Request body

- object
  - `name` string: A name your team recognizes, up to 120 characters.
  - `type` 'forbidden_terms' | 'brand_term' | 'direct_linking' | 'promo_code' | 'position_limit' | 'affiliate_id', required
  - `params` object: Parameters for the rule type; send only the ones that type uses.
    - `terms` string[]: Forbidden words or phrases.
    - `fields` string[]: Ad parts to check for terms.
    - `applies_to` 'unauthorized' | 'all_non_owned'
    - `authorized_domains` string[]
    - `extra_terms` string[]: Extra brand terms.
    - `codes` string[]: Forbidden promo codes.
    - `any_explicit_code` boolean: Also flag any other code written after the word code.
    - `allowed_codes` string[]
    - `top_positions` integer
    - `authorized_ids` string[]
  - `scope` object: Observations to check: engine, device, os, country and location, each one value or a list. Omit for every observation.
    - `engine` union: Search engine, or a list of engines combined with OR.
      - 'google' | 'bing'
      - string[]
    - `device` union: Device, or a list combined with OR.
      - 'desktop' | 'mobile'
      - string[]
    - `os` union: Operating system. unspecified matches checks that did not pin one. Must fit the chosen device.
      - 'windows' | 'macos' | 'android' | 'ios' | 'unspecified'
      - string[]
    - `country` union: ISO 3166-1 alpha-2 country code such as US, or a list.
      - string
      - string[]
    - `location` union: Saved location key: code:<location code>, name:<label> or country:<ISO code>. get_project_details lists the keys that have data.
      - string
      - string[]
  - `range` '7d' | '14d' | '30d' | '12m' | 'custom': Window ending today: 7d, 14d, 30d (default) or 12m. Use custom with from and to for fixed dates.
  - `from` string: First local day, YYYY-MM-DD (custom range).
  - `to` string: Last local day, YYYY-MM-DD, included in full (custom range).
  - `time_zone` string: IANA time zone for day boundaries, such as America/New_York. Defaults to the time zone of the person the credential acts for.

## Response `200`

What a draft rule would match, without saving it

- object
  - `window` object, required
    - `from` string, required: First local day included, YYYY-MM-DD.
    - `to` string, required: Last local day included, YYYY-MM-DD.
    - `time_zone` string, required
    - `start` string, required: Inclusive start instant, ISO 8601.
    - `end` string, required: Exclusive end instant, ISO 8601.
  - `matched_ads` integer, required
  - `advertisers` integer, required
  - `cases` integer, required: Cases the rule would open or update.
  - `truncated` boolean, required: True when only the first 20,000 saved ads were read.
  - `examples` object[], required
    - `observed_at` string, required
    - `query` string, required
    - `engine` 'google' | 'bing', required
    - `device` 'desktop' | 'mobile', required
    - `os` string, nullable, required
    - `country` string, required
    - `location` string, nullable, required
    - `position` integer, required
    - `advertiser_domain` string, required
    - `title` string, nullable, required
    - `description` string, nullable, required
    - `display_url` string, nullable, required
    - `url` string, nullable, required
    - `placement` 'top' | 'bottom', nullable, required: Where a Google ad was shown on the page; null for Bing and older observations.
    - `assets` union[], nullable, required: Ad assets shown with the ad (sitelinks, phone, promotion, price, image, extra description rows). null: not captured (older observations, imported studies); []: captured, none shown.
      - union
        - object
          - `kind` 'sitelink', required
          - `title` string, nullable, required
          - `url` string, nullable, required
          - `description` string, nullable, required
        - object
          - `kind` 'phone', required
          - `number` string, required
        - object
          - `kind` 'promotion', required
          - `text` string, required
          - `url` string, nullable, required
        - object
          - `kind` 'price', required
          - `displayed` string, nullable, required
          - `current` number, nullable, required
          - `regular` number, nullable, required
          - `max_value` number, nullable, required
          - `currency` string, nullable, required: ISO 4217 code when reported.
          - `is_range` boolean, nullable, required
        - object: The ad showed an image; it is not stored.
          - `kind` 'image', required
        - object
          - `kind` 'description_line', required
          - `text` string, required
    - `matched` string, required: What matched: terms, a code, a destination host, a position or an affiliate ID.
    - `paid_results_path` string, required: App path of the saved ads for this advertiser, market and day.
  - `request_id` string

## Other responses

- `400`: Invalid parameters, cursor or body.
- `401`: Missing, invalid, expired or revoked credential.
- `403`: The credential lacks the write scope, the plan does not include the API, or the allowance is used up.
- `404`: Unknown project, keyword or run in this account.
- `409`: The idempotency key was already used for a different request.
- `429`: Rate limit reached. Retry after the Retry-After seconds.
- `503`: The requested service or file is temporarily unavailable.

---

[API](https://skmtc.dev/adslighthouse/apis/ads-lighthouse-api.md) · [All operations](https://skmtc.dev/adslighthouse/apis/ads-lighthouse-api/llms.txt) · [OpenAPI document](https://skmtc.dev/adslighthouse/apis/ads-lighthouse-api/revisions/e1a4a40b11a9?raw)
