---
title: "Create a value rule set"
method: POST
path: "/v1/ads/value-rule-sets"
tags: ["Ad Accounts"]
---

# Create a value rule set

`POST /v1/ads/value-rule-sets`

Creates a value rule set on the ad account (Meta's `POST /act_X/value_rule_set`).
Attach the returned id to an ad set with `valueRuleSetId` on `POST /v1/ads/create` or
`PUT /v1/ads/ad-sets/{adSetId}`.

**Rule order is semantic**: rules are evaluated in array order and only the first
matching rule adjusts the bid for an overlapping audience.

`adjustValue` is an unsigned magnitude in percent; the direction lives in `adjustSign`.
`INCREASE` accepts 1-1000, `DECREASE` accepts 1-90. There is no signed field and 0 is
out of range.

`criteriaValueTypes` is positionally paired with `criteriaValues` (same length, same
order). Every type is the literal `"NONE"` except on `LOCATION`, which uses
`LOCATION_COUNTRY` / `LOCATION_REGION` / `LOCATION_CITY` / `LOCATION_COMSCORE_MARKET`
and may mix them within one criterion. Location values are Targeting-Search keys: a
two-letter country code for `LOCATION_COUNTRY`, a numeric key for the rest.

`LOCATION_DMA` was replaced by `LOCATION_COMSCORE_MARKET` on 2026-06-22 and rules using
DMAs are no longer active, so this API rejects it.

`AUDIENCE_LABEL` values (e.g. `HIGH_VALUE`) are applied to a Custom Audience in Ads
Manager. There is no API to provision them, so label strings are passed through
unvalidated and a typo produces a rule that never fires.

Ads Manager turns a rule set read-only (this API stays editable) when a rule uses more
than 2 criteria, a custom age range, or the placements `FB_MARKETPLACE`, `FB_SEARCH`,
`FB_VIDEO` or `IG_EXPLORE`.

Limits: 6 rule sets per ad account, 10 rules per set, 4 criteria per rule. The
per-account cap is enforced by Meta, not here.

## Request body

- object
  - `accountId` string, required — Zernio SocialAccount id (posting or ads variant) used to resolve the Meta token.
  - `adAccountId` string, required — Meta ad account id (act_<n>).
  - `name` string, required
  - `rules` ValueRule[], required — Evaluated in order; the first matching rule wins.
    - `id` string — Platform rule id. Echo it on `PUT` to KEEP this rule, omit it to CREATE a new one. A rule left out of the array entirely is DELETED.
    - `name` string, required
    - `adjustSign` 'INCREASE' | 'DECREASE', required — Direction of the adjustment. There is no signed value field.
    - `adjustValue` integer, required — Unsigned percentage magnitude. `INCREASE` accepts 1-1000, `DECREASE` accepts 1-90. 0 is out of range on both.
    - `status` string — Meta returns `ACTIVE` here but documents no enum for the field. Treat it as a passthrough: echo whatever the `GET` returned, and do not synthesize values.
    - `criteria` ValueRuleCriterion[], required — All criteria on a rule must match for the rule to fire.
      - `id` string — Platform criterion id. Echo it on `PUT` to KEEP this criterion, omit it to CREATE a new one. A criterion left out of the array entirely is DELETED.
      - `criteriaType` 'AGE' | 'GENDER' | 'OS_TYPE' | 'DEVICE_PLATFORM' | 'LOCATION' | 'PLACEMENT' | 'OMNI_CHANNEL' | 'AUDIENCE_LABEL', required — The dimension being matched. `OMNI_CHANNEL` (conversion location: APP, INSTANT_FORM, PHONE_CALL, WEBSITE) is accepted even though Meta's own enum table omits it.
      - `operator` 'CONTAINS', required — Required on every criterion. `CONTAINS` is currently the only value Meta supports.
      - `criteriaValues` string[], required — The values to match. `AGE` takes ranges such as `18-24`, `18+` or a custom `18-26`; a range whose upper bound is 65 is NOT allowed (use `18+` instead of `18-65`). `LOCATION` takes Targeting-Search keys: a two-letter country code for `LOCATION_COUNTRY`, a numeric key for region / city / comScore market. `AUDIENCE_LABEL` takes labels such as `HIGH_VALUE`, which are applied to a Custom Audience in Ads Manager: there is no API to provision them, so they are passed through unvalidated.
      - `criteriaValueTypes` string[], required — One entry per `criteriaValues` entry, in the same order. The literal `"NONE"` for every criteriaType except `LOCATION`, which uses `LOCATION_COUNTRY`, `LOCATION_REGION`, `LOCATION_CITY` or `LOCATION_COMSCORE_MARKET` and MAY mix them within one criterion. `LOCATION_DMA` was replaced by `LOCATION_COMSCORE_MARKET` on 2026-06-22 and is rejected by this API.

## Response `201`

Value rule set created

- object
  - `adAccountId` string
  - `valueRuleSetId` string, nullable — The new rule set id. Meta does not document the create response body, so this is null on the (unobserved) case where it omits the id.

## Other responses

- `400` — Invalid input, or Meta rejected the create (per-account rule-set cap, ineligible criteria, or an account that is not enabled for value rules)
- `401` — Unauthorized
- `501` — Only supported on Meta (facebook/instagram)

---

[API](https://skmtc.net/zernio/apis/zernio-api.md) · [All operations](https://skmtc.net/zernio/apis/zernio-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/zernio/zernio-api/versions/f81ca70ea6b9/schema)
