---
title: "Create an always-on rule"
method: POST
path: "/api/v1/campaigns/{campaign_id}/routing-rules"
tags: ["experiments"]
---

# Create an always-on rule

`POST /api/v1/campaigns/{campaign_id}/routing-rules`

## Request

- Base URL: `https://api.outrival.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.outrival.com/api/v1/campaigns/{campaign_id}/routing-rules`
- Auth: HTTP bearer

Store a new rule. It is live immediately — there is no launch step.

That is the difference from an experiment, not an omission: a rule has no
split to allocate and no conclusion to reach, so there is nothing for a
launch gate to check. Membership is dynamic, so the first contacts it
affects are the ones resolved after this returns.

## Path parameters

- `campaign_id` string, required

## Request body

- CreateRoutingRuleRequest: A new always-on rule. ``pin_overrides`` maps a component type to a stored version of it — the change this rule makes for whoever it targets. It must NOT be empty: a rule that changes nothing would still claim every contact it matches, ahead of every experiment, so the service refuses it with a 422 (see ``RoutingRuleService.create_rule``).
  - `name` string, required: What this rule is for
  - `targeting_rules` TargetingCondition[]: Conditions a contact must meet; empty targets everyone
    - `field` string, required: Contact field to compare
    - `operator` string, required: One of the nine operators the engine matches on
    - `value` string, required: What the field is compared against
  - `pin_overrides` object: {component: version id} — what this rule changes
  - `priority` integer, nullable: Optional unique slot among this campaign's active rules. Omitted: the service assigns the next free number. Priority is not how same-section collisions are decided — those are refused.

## Response `201`

Successful Response

- object

## Other responses

- `400`: Invalid campaign ID format
- `403`: User may not edit this campaign
- `404`: Campaign not found
- `409`: Another live rule already pins one of these sections, or Experiments V2 is not enabled in this environment. The detail names the holder. Stop that rule before pinning the section again.
- `422`: The rule could not be stored: no pinned changes at all, an operator the engine cannot match on, a pin on a section that is not pinnable (the detail names it), a pin that is not a component version of this campaign, or a priority another active rule already holds

## Changes

- **2026-09-03** `219a10b80707`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/outrival/apis/outrival-api/changes/api/v1/campaigns/:campaign_id/routing-rules/post.md)

---

[API](https://skmtc.dev/outrival/apis/outrival-api.md) - [All operations](https://skmtc.dev/outrival/apis/outrival-api/llms.txt) - [OpenAPI document](https://skmtc.dev/outrival/apis/outrival-api/revisions/f27d90300b5e?raw)
