# Create campaign

> Promote a published Page post as a paused campaign.

Canonical: <https://www.tryadeli.com/docs/api/ads/create-campaign>

`POST https://app.tryadeli.com/api/v1/ads/campaigns`

Authorization: `Bearer <API key>` — see [Authentication](https://www.tryadeli.com/docs/authentication)

Promotes a post the connected Page already published, creating a campaign, ad
set, creative and ad. **Everything is created paused.** Nothing delivers and
nothing spends until you activate it, which is [a separate call](https://www.tryadeli.com/docs/api/ads/update-status).

An `Idempotency-Key` header is required. This is the only endpoint in the API
where a retry has a cost, so the same key replays the original result rather
than creating a second campaign: `200` with the same object ids when the
campaign was built, `409 campaign_create_failed` with the original reason when
it failed, and `409 campaign_create_in_progress` while it is still being
created. To retry a failed create, send a new key.

**Body**

| Name           | Type     | Required | Description                                                            |
| -------------- | -------- | -------- | ---------------------------------------------------------------------- |
| `adAccountId`  | `string` | Yes      | The ad account to create in.                                           |
| `pagePostId`   | `string` | Yes      | The post id alone; the Page half of Meta's story id is server-derived. |
| `dailyBudget`  | `number` | Yes      | Whole currency units, as Meta expects: 25 means 25.00.                 |
| `startDate`    | `date`   | Yes      | YYYY-MM-DD.                                                            |
| `endDate`      | `date`   | Yes      | YYYY-MM-DD, on or after startDate.                                     |
| `campaignName` | `string` | Yes      | Shown in Ads Manager.                                                  |

Responds `201` with the created object ids, Adeli's `campaign` record (its `id` is the `campaignRecordId` used by [Activate, pause or resume](https://www.tryadeli.com/docs/api/ads/update-status)), and a
`preview` when Meta returns one: Meta's `body` markup, plus the `url`, `width`
and `height` of the facebook.com preview page it wraps. Embed `url` in an
iframe that allows scripts; the page renders blank without them. If a step fails, Adeli deletes what it
already created and responds `502 campaign_create_failed` with the failing `step` and any
`orphanedObjectIds` it could not remove — those are paused, so they cost
nothing, but they are named so you can find them in Ads Manager.

## Request examples

**cURL**

```bash
curl --fail-with-body -X POST "https://app.tryadeli.com/api/v1/ads/campaigns?accountId=00000000-0000-0000-0000-000000000000" \
  -H "Authorization: Bearer $ADELI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: fall-launch-boost" \
  -d '{
  "adAccountId": "act_1234567890",
  "pagePostId": "987654321098765",
  "dailyBudget": 25,
  "startDate": "2026-11-01",
  "endDate": "2026-11-07",
  "campaignName": "Fall launch"
}'
```

**JavaScript**

```javascript
const response = await fetch("https://app.tryadeli.com/api/v1/ads/campaigns?accountId=00000000-0000-0000-0000-000000000000", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ADELI_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "fall-launch-boost",
  },
  body: JSON.stringify({
    adAccountId: "act_1234567890",
    pagePostId: "987654321098765",
    dailyBudget: 25,
    startDate: "2026-11-01",
    endDate: "2026-11-07",
    campaignName: "Fall launch",
  }),
});
console.log(await response.json());
```

**Python**

```python
import os

import requests

response = requests.post(
    "https://app.tryadeli.com/api/v1/ads/campaigns",
    headers={"Authorization": f"Bearer {os.environ['ADELI_API_KEY']}", "Idempotency-Key": "fall-launch-boost"},
    params={
        "accountId": "00000000-0000-0000-0000-000000000000",
    },
    json={
        "adAccountId": "act_1234567890",
        "pagePostId": "987654321098765",
        "dailyBudget": 25,
        "startDate": "2026-11-01",
        "endDate": "2026-11-07",
        "campaignName": "Fall launch",
    },
)
print(response.json())
```

## Responses

### 201

```json
{
  "campaign": {
    "id": "00000000-0000-4000-8000-000000000020",
    "profileId": "00000000-0000-4000-8000-000000000002",
    "facebookConnectionId": "00000000-0000-0000-0000-000000000000",
    "adAccountId": "act_1234567890",
    "pageId": "123456789012345",
    "pagePostId": "987654321098765",
    "idempotencyKey": "fall-launch-boost",
    "campaignId": "120210000000000001",
    "adSetId": "120210000000000002",
    "creativeId": "120210000000000003",
    "adId": "120210000000000004",
    "status": "paused",
    "failureReason": null,
    "createdAt": "2026-10-09T16:00:00.000Z",
    "updatedAt": "2026-10-09T16:00:04.000Z"
  },
  "objects": {
    "campaignId": "120210000000000001",
    "adSetId": "120210000000000002",
    "creativeId": "120210000000000003",
    "adId": "120210000000000004"
  },
  "preview": {
    "format": "MOBILE_FEED_STANDARD",
    "body": "<iframe src=\"https://www.facebook.com/ads/api/preview_iframe.php?d=AQ...&amp;t=AQ...\" width=\"320\" height=\"570\" scrolling=\"yes\" style=\"border: none;\"></iframe>",
    "url": "https://www.facebook.com/ads/api/preview_iframe.php?d=AQ...&t=AQ...",
    "width": 320,
    "height": 570
  },
  "replayed": false
}
```

### 400

```json
{
  "error": {
    "code": "invalid_request",
    "message": "Invalid campaign request",
    "details": [
      { "code": "custom", "path": ["startDate"], "message": "startDate must be tomorrow (UTC) or later" }
    ]
  }
}
```

### 409

```json
{
  "error": {
    "code": "campaign_create_in_progress",
    "message": "This campaign is still being created",
    "details": { "campaignRecordId": "00000000-0000-4000-8000-000000000020", "replayed": true }
  }
}
```
