# Organization API: Organizations & Members: Campaigns

> The 7 Organization API operations for campaigns.

Source: https://www.coritan.com/docs/api/reference/organizations/organizations-members/campaigns/

Part of [Organizations & Members](/docs/api/reference/organizations/organizations-members/).

## Operations

| Method | Path | Summary |
| --- | --- | --- |
| GET | [`/api/v1/orgs/{org_slug}/campaigns`](#op-get-api-v1-orgs-org-slug-campaigns) | List the campaign links |
| POST | [`/api/v1/orgs/{org_slug}/campaigns`](#op-post-api-v1-orgs-org-slug-campaigns) | Save a campaign link |
| POST | [`/api/v1/orgs/{org_slug}/campaigns/preview`](#op-post-api-v1-orgs-org-slug-campaigns-preview) | Check a campaign link and build its address without saving it |
| GET | [`/api/v1/orgs/{org_slug}/campaigns/results`](#op-get-api-v1-orgs-org-slug-campaigns-results) | Read what each campaign brought in |
| PATCH | [`/api/v1/orgs/{org_slug}/campaigns/{campaign_id}`](#op-patch-api-v1-orgs-org-slug-campaigns-campaign-id) | Change or archive a campaign link |
| DELETE | [`/api/v1/orgs/{org_slug}/campaigns/{campaign_id}`](#op-delete-api-v1-orgs-org-slug-campaigns-campaign-id) | Delete a campaign link |
| GET | [`/api/v1/orgs/{org_slug}/campaigns/{campaign_id}/results`](#op-get-api-v1-orgs-org-slug-campaigns-campaign-id-results) | Read what one campaign brought in |

### List the campaign links {#op-get-api-v1-orgs-org-slug-campaigns}

`GET /api/v1/orgs/{org_slug}/campaigns`

The organization's saved campaign links, newest first.

Needs the Billing, Admin or Owner role. A campaign is a landing page with the UTM words that tag it and an
optional coupon. Every campaign has all its fields, `archived` (true once it was archived) and `url`, the
full link to copy: the storefront address, `base_path`, the UTM words in the order `utm_source`,
`utm_medium`, `utm_campaign`, `utm_term`, `utm_content`, then `coupon`. The words are percent encoded. An
organization with no storefront address gets the path and query alone. `count` is how many campaigns
match before `limit` and `offset` apply, and `max_campaigns` is the most an organization keeps.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `org_slug` | path | string | yes |  |
| `status` | query | string | no | `all` (the default), `active` or `archived`. Default: `all`. |
| `q` | query | string or null | no | Only campaigns whose name or campaign word holds this text, ignoring capitals. |
| `limit` | query | integer | no | Campaigns to return, 1 to 200. Left out, 100. Default: `100`. |
| `offset` | query | integer | no | Campaigns to skip, for the next page. Default: `0`. |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Save a campaign link {#op-post-api-v1-orgs-org-slug-campaigns}

`POST /api/v1/orgs/{org_slug}/campaigns`

Save a campaign link and answer it, with its `url`.

Needs the Billing, Admin or Owner role. `name`, `utm_source`, `utm_medium` and `utm_campaign` are
required. A bad value answers 422 with `detail`, the sentence to show, and `field`, the input it belongs
to. A name another campaign already has, in any capitals, answers 409 with `field` `name`. An
organization keeps at most 500 campaigns, and the 501st answers 409. A `coupon_code` must be a coupon of
this organization. The change is recorded in the audit log as `campaign.created`.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `org_slug` | path | string | yes |

#### Request body

`application/json` (required)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string or null | no | What you call the campaign, at most 120 characters. Each campaign in an organization has its own name, and two names that differ only in capitals count as one. |
| `base_path` | string or null | no | The page the link opens: a path on your storefront that starts with `/`, at most 400 characters, such as `/pricing`. It holds no host, scheme, fragment, backslash, space or control character, and at most one `?`. A query in it is kept and the UTM words go after it. Left out when you create a campaign, it is `/`. |
| `utm_source` | string or null | no | Where the visit comes from, such as `newsletter`. At most 80 characters, with no `&`, `=`, `#`, `?` or control character. |
| `utm_medium` | string or null | no | How the link is delivered, such as `email`. At most 80 characters, with the same limits as the source. |
| `utm_campaign` | string or null | no | The word the reports group by, at most 120 characters, with the same limits as the source. A visit or order whose campaign is this word belongs to the campaign, whatever its capitals. |
| `utm_term` | string or null | no | The keyword or audience, at most 120 characters. Empty or null for none. |
| `utm_content` | string or null | no | Tells two links of one campaign apart, at most 120 characters. Empty or null for none. |
| `coupon_code` | string or null | no | A coupon of this organization that the link applies, as `?coupon=`. It must exist. Empty or null for none. |
| `notes` | string or null | no | A note for your team, at most 500 characters. Empty or null for none. |

#### Responses

| Status | Meaning |
| --- | --- |
| `201` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Check a campaign link and build its address without saving it {#op-post-api-v1-orgs-org-slug-campaigns-preview}

`POST /api/v1/orgs/{org_slug}/campaigns/preview`

Build the link for the fields sent, and list what is wrong with them. Saves nothing.

Needs the Billing, Admin or Owner role. Send the same body as a save; `name` may be left out. The answer
is `{url, problems}`. `problems` is a list of `{field, detail}` with every problem found, and `url` is null
while there is one. The check is the one a save makes, a repeated name and an unknown coupon included.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `org_slug` | path | string | yes |

#### Request body

`application/json` (required)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string or null | no | What you call the campaign, at most 120 characters. Each campaign in an organization has its own name, and two names that differ only in capitals count as one. |
| `base_path` | string or null | no | The page the link opens: a path on your storefront that starts with `/`, at most 400 characters, such as `/pricing`. It holds no host, scheme, fragment, backslash, space or control character, and at most one `?`. A query in it is kept and the UTM words go after it. Left out when you create a campaign, it is `/`. |
| `utm_source` | string or null | no | Where the visit comes from, such as `newsletter`. At most 80 characters, with no `&`, `=`, `#`, `?` or control character. |
| `utm_medium` | string or null | no | How the link is delivered, such as `email`. At most 80 characters, with the same limits as the source. |
| `utm_campaign` | string or null | no | The word the reports group by, at most 120 characters, with the same limits as the source. A visit or order whose campaign is this word belongs to the campaign, whatever its capitals. |
| `utm_term` | string or null | no | The keyword or audience, at most 120 characters. Empty or null for none. |
| `utm_content` | string or null | no | Tells two links of one campaign apart, at most 120 characters. Empty or null for none. |
| `coupon_code` | string or null | no | A coupon of this organization that the link applies, as `?coupon=`. It must exist. Empty or null for none. |
| `notes` | string or null | no | A note for your team, at most 500 characters. Empty or null for none. |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Read what each campaign brought in {#op-get-api-v1-orgs-org-slug-campaigns-results}

`GET /api/v1/orgs/{org_slug}/campaigns/results`

What every saved campaign brought in over a period, and the campaign words no saved campaign names.

Needs the Billing, Admin or Owner role. The period is `from` to `to` in the brand's time zone, the last 30
days when left out, and at most 366 days. A campaign owns the visits, sign-ups and orders whose
`utm_campaign` is its own, ignoring capitals. The figures are the acquisition report's: a visit is a stored
session with bots left out, a sign-up is a customer whose last touch named the campaign, an order is a paid
order that is not free, and `revenue_minor` is the invoice total without tax in `currency`'s minor units.
Orders and revenue are counted in one currency and never added across currencies: `currencies` names every
currency with an order in the period. `conversion_rate_bp` is orders over visits in basis points, so 123 is
1.23 percent. `visits_complete` is false when the period starts more than 180 days ago, because sessions are
kept for 180 days. `unmatched` lists the campaign words of the period that no saved campaign names, the
biggest first, at most `limit`.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `org_slug` | path | string | yes |  |
| `from` | query | string (date) or null | no | First day of the period, YYYY-MM-DD, in the brand's time zone. Left out, 29 days before the last day, so the period is the last 30 days. A period is at most 366 days. |
| `to` | query | string (date) or null | no | Last day of the period, YYYY-MM-DD, in the brand's time zone. Left out, today. |
| `currency` | query | string or null | no | A three letter currency code. Orders and revenue are counted in this one currency and never added across currencies. Left out, the currency with the most revenue in the period, else the brand's own. |
| `limit` | query | integer | no | Campaign words in `unmatched`, 1 to 200. Left out, 20. The saved campaigns are always all listed. Default: `20`. |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Change or archive a campaign link {#op-patch-api-v1-orgs-org-slug-campaigns-campaign-id}

`PATCH /api/v1/orgs/{org_slug}/campaigns/{campaign_id}`

Change the fields of a campaign that were sent, or archive it with `archived`, and answer it.

Needs the Billing, Admin or Owner role. Only the fields sent are checked and changed, by the rules of a
save. A null or empty `utm_term`, `utm_content`, `coupon_code` or `notes` clears it. Saving what is
already there changes nothing and writes no audit entry. A change is recorded as `campaign.updated` with
the names of the fields that changed. A campaign of another organization answers 404.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `campaign_id` | path | integer | yes |
| `org_slug` | path | string | yes |

#### Request body

`application/json` (required)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string or null | no | What you call the campaign, at most 120 characters. Each campaign in an organization has its own name, and two names that differ only in capitals count as one. |
| `base_path` | string or null | no | The page the link opens: a path on your storefront that starts with `/`, at most 400 characters, such as `/pricing`. It holds no host, scheme, fragment, backslash, space or control character, and at most one `?`. A query in it is kept and the UTM words go after it. Left out when you create a campaign, it is `/`. |
| `utm_source` | string or null | no | Where the visit comes from, such as `newsletter`. At most 80 characters, with no `&`, `=`, `#`, `?` or control character. |
| `utm_medium` | string or null | no | How the link is delivered, such as `email`. At most 80 characters, with the same limits as the source. |
| `utm_campaign` | string or null | no | The word the reports group by, at most 120 characters, with the same limits as the source. A visit or order whose campaign is this word belongs to the campaign, whatever its capitals. |
| `utm_term` | string or null | no | The keyword or audience, at most 120 characters. Empty or null for none. |
| `utm_content` | string or null | no | Tells two links of one campaign apart, at most 120 characters. Empty or null for none. |
| `coupon_code` | string or null | no | A coupon of this organization that the link applies, as `?coupon=`. It must exist. Empty or null for none. |
| `notes` | string or null | no | A note for your team, at most 500 characters. Empty or null for none. |
| `archived` | boolean or null | no | `true` archives the campaign and `false` brings it back. An archived campaign keeps its link and its results. |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Delete a campaign link {#op-delete-api-v1-orgs-org-slug-campaigns-campaign-id}

`DELETE /api/v1/orgs/{org_slug}/campaigns/{campaign_id}`

Delete a campaign link. The visits and orders that carried its words stay in the reports.

Needs the Billing, Admin or Owner role. Archive a campaign instead to keep its link and its results in the
list. A campaign of another organization answers 404. Recorded as `campaign.deleted`.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `campaign_id` | path | integer | yes |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Read what one campaign brought in {#op-get-api-v1-orgs-org-slug-campaigns-campaign-id-results}

`GET /api/v1/orgs/{org_slug}/campaigns/{campaign_id}/results`

What one campaign brought in over a period and over the period before it.

Needs the Billing, Admin or Owner role. The figures and their definitions are those of `GET results`.
`totals` holds `visits`, `signups`, `orders`, `new_customers`, `revenue_minor` and `conversion_rate_bp`, and
`totals.previous` holds the same for the comparison period, or null when `compare` is `none`. A campaign of
another organization answers 404.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `campaign_id` | path | integer | yes |  |
| `org_slug` | path | string | yes |  |
| `from` | query | string (date) or null | no | First day of the period, YYYY-MM-DD, in the brand's time zone. Left out, 29 days before the last day, so the period is the last 30 days. A period is at most 366 days. |
| `to` | query | string (date) or null | no | Last day of the period, YYYY-MM-DD, in the brand's time zone. Left out, today. |
| `compare` | query | string or null | no | `previous` (the default) sets every total against the same number of days just before the period, and a calendar month against the month before it. `none` leaves the comparison out. Default: `previous`. |
| `currency` | query | string or null | no | A three letter currency code. Orders and revenue are counted in this one currency and never added across currencies. Left out, the currency with the most revenue in the period, else the brand's own. |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |
