# Campaign create (/guides/campaign-create)

Omitted fields are filled server-side. **Do not copy the full `filters` object from GET responses** — only send what you need.

## Create defaults [#create-defaults]

| Field | Default when omitted |
|-------|----------------------|
| `active` | `true` |
| `filters.facebook`, `google`, `tiktok`, `kwai`, `taboola`, `pinterest`, `yandex`, `mgid`, `outbrain`, `sms`, `revcontent`, `adskeeper`, `newsbreak` | `false` |
| `filters.adspy`, `bots`, `proxy`, `cloakup_ai` | `true` |
| `filters.deny_always` | `false` |
| `filters.state` | `{ "allow": true, "states": [] }` |
| `filters.city` | `{ "allow": true, "cities": [] }` |
| `filters.network_type` | `{ "allow": true, "types": [] }` |
| `filters.device` | `{ "allow": true, "devices": [] }` |
| `filters.geolocation.allow` | `true` |
| `filters.referer.allow` | `true` |
| `filters.query.allow` | `true` |
| `filters.query.remove_params` | `false` |
| `filters.domain.allow`, `browser.allow`, `browser_language.allow`, `isp.allow`, `os.allow`, `user_agent.allow` | `true` |

**Still required** (no default for the key itself): `name`, `mode`, `pages`, `domain`, `alias`, and in `filters`: `geolocation`, `referer`, `query`, `domain`, `browser`, `browser_language`, `isp`, `os`, `user_agent`, `blacklist`.

Inside required objects you may omit nested defaults (e.g. send `"domain": {}`, `"referer": { "block_null": true, "domains": [] }`).

To target a single ad network, send only that network as `true` (e.g. `"facebook": true`). All other networks default to `false`.

## Pages / offers business rules [#pages--offers-business-rules]

Returns `422` if violated:

| Rule | Detail |
|------|--------|
| Offer `share` | Within each segmentation group, `share` values must sum to **exactly 100**. Group key = sorted `segmentation.country` join, or `"fallback"` when country list empty/missing. |
| Fallback offer | At least **one** offer must have no country segmentation (empty/missing `segmentation.country`). |
| `mode: "basic"` | Exactly **one** ad-network flag `true`, and `filters.device.devices` must have **≥ 1** entry. |
| `mode: "advanced"` | Zero or one ad network; empty `device.devices` allowed. |

## Minimal example [#minimal-example]

Production-safe body with only non-default values:

```json
{
  "name": "My Campaign",
  "mode": "advanced",
  "domain": null,
  "alias": null,
  "pages": {
    "white": { "type": "content", "content": "safe.html" },
    "offers": [{ "type": "content", "content": "offer.html", "share": 100 }]
  },
  "filters": {
    "facebook": true,
    "geolocation": { "countries": ["BR"] },
    "referer": { "block_null": true, "domains": [] },
    "query": { "condition": "some", "params": {}, "rules": {} },
    "domain": {},
    "browser": {},
    "browser_language": { "languages": ["pt-br"] },
    "isp": {},
    "os": {},
    "user_agent": {},
    "blacklist": []
  }
}
```

Omitted here (defaults apply): `active`, all other ad networks, `deny_always` (`false`), `bots`, `proxy`, `adspy`, `cloakup_ai`, `state`, `city`, `network_type`, `device`, and every `allow` / `remove_params` flag.

## Example with query params [#example-with-query-params]

Same production-safe body, plus URL param matching. This campaign allows traffic when the URL has `utm_source=google` **or** the custom token `asiudhasudhasd=123u1basj`.

Visitor URL that matches:

```text
https://track.example.com/slug?utm_source=google&asiudhasudhasd=123u1basj
```

`"asiudhasudhasd": "equals"` is the **comparison**, not the value. In `params` the value is an array: `"asiudhasudhasd": ["123u1basj"]`. A plain string (`"asiudhasudhasd": "123u1basj"`) is invalid. See [Campaign filters](/guides/campaign-filters#url-query-params-filtersquery) for `contains`, `starts_with`, `ends_with`, `every`, and more copy-paste examples.

```json
{
  "name": "My Campaign",
  "mode": "advanced",
  "domain": null,
  "alias": null,
  "pages": {
    "white": { "type": "content", "content": "safe.html" },
    "offers": [{ "type": "content", "content": "offer.html", "share": 100 }]
  },
  "filters": {
    "facebook": true,
    "geolocation": { "countries": ["BR"] },
    "referer": { "block_null": true, "domains": [] },
    "query": {
      "condition": "some",
      "params": {
        "utm_source": ["google"],
        "asiudhasudhasd": ["123u1basj"]
      },
      "rules": {
        "utm_source": "equals",
        "asiudhasudhasd": "equals"
      }
    },
    "domain": {},
    "browser": {},
    "browser_language": { "languages": ["pt-br"] },
    "isp": {},
    "os": {},
    "user_agent": {},
    "blacklist": []
  }
}
```

<Callout type="warn">

For test/review mode only, set `"deny_always": true`. See [Production safety](/guides/production-safety).

</Callout>

## Update (PUT) [#update-put]

`PUT /v1/campaigns/:id` uses the same full body as create. This is **not** a partial PATCH — send the complete `CampaignBody`.
