# Campaigns API reference

Manage campaign content changes, audience references, goals, and holdback settings in the project draft.

Available on the Scale and Pro plans.

Use campaigns to change content on existing website pages for selected audiences. This API flattens a campaign's variants and actions into a `changes` array.

## Authentication and campaign operations

Paths below follow `https://api.rightmessage.com/v1/{teamPid}`. GET requires `read` or `write`; mutations require `write`. The `*` ability satisfies both. The [shared request conventions](https://rightmessage.com/help/rest-api-overview#base-url-and-authentication) cover bearer authentication, headers, project access, and rate limits.

| Method and path                      | Request                             | Success                    |
| ------------------------------------ | ----------------------------------- | -------------------------- |
| GET `/campaigns`                     | No filters or pagination parameters | 200, `{"data":[RESOURCE]}` |
| GET `/campaigns/{campaign}`          | Resource ID from the list           | 200, `{"data":RESOURCE}`   |
| POST `/campaigns`                    | Create body below                   | 201, `{"data":RESOURCE}`   |
| PUT or PATCH `/campaigns/{campaign}` | Partial body below                  | 200, `{"data":RESOURCE}`   |
| DELETE `/campaigns/{campaign}`       | No body                             | 204, empty body            |

PUT and PATCH have the same partial-update behavior. An omitted top-level field retains its value. A collection with no resources returns `{"data":[]}`. Reads return the draft when one exists, otherwise the stable configuration.

## Errors and draft effects

The [shared error contract](https://rightmessage.com/help/rest-api-overview#error-contract) applies. Invalid request fields return 422 with `message` and field-keyed `errors`. Full-configuration validation can return 500 instead.

Mutations save a draft, not live changes. [Publishing](https://rightmessage.com/help/rest-api-publishing) applies the whole project draft, including edits made elsewhere. The [draft contract](https://rightmessage.com/help/rest-api-overview#draft-and-live-configuration) covers snapshots, dashboard updates, and save failures.

## Campaign fields

| Field                | Type and validation                                          | Create default                   |
| -------------------- | ------------------------------------------------------------ | -------------------------------- |
| `name`               | Required on create, optional on update. String, maximum 255. | Required                         |
| `is_active`          | Boolean                                                      | true                             |
| `base_url`           | Nullable string, maximum 500. No URL-format validation.      | null                             |
| `testing`            | Object                                                       | Enabled with 10 percent holdback |
| `testing.is_enabled` | Boolean                                                      | true                             |
| `testing.withhold`   | Integer, 0 through 100                                       | 10                               |
| `goal_ids`           | Array of strings                                             | \[]                              |
| `outcome`            | `any_goal` or `primary_goal`                                 | any\_goal                        |
| `changes`            | Array of change objects                                      | \[]                              |

A supplied `goal_ids` list replaces the list. With `primary_goal`, the first attached goal is primary. A supplied `testing` object replaces the stored object, except that omitted `withhold` retains its previous value. Configuration repair fills an omitted `is_enabled` with true, even if testing was previously disabled. Send both testing fields when changing testing settings.

## Change objects

Every field below belongs in each `changes[]` item. Except for selector requirements, every field is optional and nullable.

| Field                           | Type and meaning                                                                                                                                                                                         |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                            | String identifying the stored action. Omit for a new action.                                                                                                                                             |
| `variant_id`                    | String identifying its stored variant. Use with `id` to disambiguate repeated legacy action IDs.                                                                                                         |
| `selector`                      | CSS-selector string. Required on create unless `targeting` is supplied. On update, required unless `id` or `targeting` is supplied.                                                                      |
| `targeting`                     | Object with `mode` of `selector` or `fingerprint`; optional `selector`, `fallbackSelector`, and stored `fingerprint`. Preserve returned Smart Match fingerprints rather than constructing a partial one. |
| `segment_ids`                   | Comma-separated segment ID string, not an array. Every named segment must exist in this project's current configuration. Empty means the default audience.                                               |
| `page`                          | Comma-separated domain/path strings such as `example.com/pricing, example.com/demo`. Do not include a URL scheme. A bare domain uses `*` as its path; a leading slash uses any domain.                   |
| `content`                       | String. Plain content replaces text. If every nonblank line has `/find/replace/` form, the service creates find-and-replace entries.                                                                     |
| `visibility`                    | `show` or `hide`                                                                                                                                                                                         |
| `style`                         | Object of style modifications                                                                                                                                                                            |
| `attr`                          | Object of attribute modifications                                                                                                                                                                        |
| `add_classes`, `remove_classes` | Comma-separated class-name strings                                                                                                                                                                       |

New changes with the same ordered segment-ID list share a variant. Use the same segment ordering throughout a create request; differently ordered lists can create separate variants even when they name the same audience. Audience rules for new variants require all named segments. A new change with an omitted or null `page` applies to all domains and paths; its returned page string is `*/*`.

### Smart Match fingerprint schema

`targeting.mode` is required when a targeting object is stored. `targeting.selector` and `targeting.fallbackSelector` are strings. A `targeting.fingerprint` object requires `text`, which requires string `content`. Its optional `matchType` is `exact`, `contains`, or `startsWith`, defaulting to exact.

The remaining fingerprint sections are optional objects:

| Section     | Child fields                                                                                                                              |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `visual`    | `fontSize` with numeric `min` and `max`; `fontWeight` with numeric `min`; `positionY` with numeric `min` and `max`; boolean `isAboveFold` |
| `element`   | String `tagName`; string-array `candidateTags`, default \[]                                                                               |
| `structure` | Integer `siblingIndex`, `siblingCount`, and `depth`; string `parentChain`                                                                 |
| `semantics` | Nullable strings `id`, `ariaRole`, and `ariaLabel`; nullable object `dataAttributes`; string-array `meaningfulClasses`, default \[]       |
| `content`   | Integer `charCount` and `wordCount`; string `textPrefix`                                                                                  |

These declarations do not impose a maximum fingerprint size or a numeric range on visual measurements. A returned fingerprint records a specific element. Reusing its fields unchanged preserves the stored targeting representation.

## Updating changes without losing content

Omitting `changes` leaves every stored action untouched. Supplying it defines the new action list. Stored actions omitted from that list are removed, along with variants whose actions were all omitted. Variants that already had no actions are retained because the flat representation cannot name them.

For a retained action, send its returned `id` and `variant_id`. Omitted fields retain their stored values, and unchanged returned values preserve the original representation. Explicit null clears content, targeting, style, attributes, or classes; a null `selector` becomes an empty selector, a null `segment_ids` moves the action to the default audience, and a null `page` resets targeting to all pages. This does not make the whole `changes` list a patch.

A duplicate action ID, a mismatched variant ID, an ambiguous repeated legacy ID, or an unknown ID without new targeting can return 422 under `errors.changes`. Unknown segment references return 422 under the matching `changes.N.segment_ids` path. Do not retry a partial list as though it were an append operation.

## Campaign response fields

The response includes `id`, `name`, `is_active`, `base_url`, `testing`, `goal_ids`, `changes`, and `outcome` when stored. Each change includes every key in the change table. Missing optional values serialize as null. The service generates `cpn_` campaign IDs, variant IDs, and action IDs.

Deleting a campaign removes it from the draft. Publishing activates or removes the campaign on the website. Campaign testing settings are not the separate flow/question/offer A/B-test lifecycle.

## Illustrative requests and responses

These illustrative examples use the fictional WorkForge project. The same resource schema covers every CRUD response.

```http
GET /v1/123456/campaigns HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

GET /v1/123456/campaigns/cpn_example1 HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

POST /v1/123456/campaigns HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Accept: application/json

{
	"name": "WorkForge campaign",
	"base_url": "https://example.com/pricing"
}

PATCH /v1/123456/campaigns/cpn_example1 HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
Accept: application/json

{
	"name": "WorkForge updated"
}

DELETE /v1/123456/campaigns/cpn_example1 HTTP/1.1
Host: api.rightmessage.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json
```

The PATCH example also works with PUT. The create, item-read, and update envelopes have this shape. The list places these resource objects in its `data` array. An update returns the updated values. DELETE returns no JSON.

```json
{
	"data": {
		"id": "cpn_example1",
		"name": "WorkForge campaign",
		"is_active": true,
		"base_url": "https://example.com/pricing",
		"testing": {
			"is_enabled": true,
			"withhold": 10
		},
		"goal_ids": [],
		"outcome": "any_goal",
		"changes": []
	}
}
```
