> ## Documentation Index
> Fetch the complete documentation index at: https://docs.makelocalads.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create an ad campaign

> Generate a set of static ad creatives from a product and campaign prompt.

Create an ad campaign when you want LocalAds to turn one campaign direction
into several distinct static ad concepts. LocalAds combines your prompt with
the saved product and brand context, then generates the creatives
asynchronously.

Each requested creative consumes one credit.

## Before you start

You need:

* an API key with `campaigns:generate`
* a product in LocalAds
* enough credits for every requested creative

## Start a campaign

```bash theme={null}
curl --request POST \
  --url https://makelocalads.com/api/v1/campaigns \
  --header "Authorization: Bearer $LOCALADS_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "product_id": "a1516a75-9be5-461a-93af-c1896a0a3127",
    "prompt": "Create a premium campaign focused on the product craftsmanship and gift appeal.",
    "language": "English",
    "creative_count": 10
  }'
```

```javascript theme={null}
const response = await fetch("https://makelocalads.com/api/v1/campaigns", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.LOCALADS_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    product_id: "a1516a75-9be5-461a-93af-c1896a0a3127",
    prompt:
      "Create a premium campaign focused on the product craftsmanship and gift appeal.",
    language: "English",
    creative_count: 10,
  }),
});

const campaign = await response.json();
```

`prompt` is required and can contain up to 2,000 characters. Describe the
audience, angle, offer, visual tone, or other direction that should shape the
campaign.

`language` defaults to `English`. `creative_count` defaults to `10` and can be
`3`, `5`, `10`, `15`, `20`, `25`, or `30`.

For production integrations, you can optionally include an `Idempotency-Key`
header. Reuse the same key when retrying the same request after a network
failure:

```bash theme={null}
--header "Idempotency-Key: campaign-order-1042"
```

Omitting the header creates and charges for a new campaign on every request.

LocalAds returns `202 Accepted` and a `Location` header:

```http theme={null}
Location: /api/v1/campaigns/84b92447-425f-4d2a-9ba1-7d67bf802332
```

```json theme={null}
{
  "id": "84b92447-425f-4d2a-9ba1-7d67bf802332",
  "brand_id": "1423f915-beca-4c53-a5e4-7c8c99537be9",
  "product_id": "a1516a75-9be5-461a-93af-c1896a0a3127",
  "name": "Create a premium campaign focused on",
  "status": "queued",
  "requested_creative_count": 10,
  "completed_creative_count": 0,
  "failed_creative_count": 0,
  "creatives": [
    {
      "id": "19025a65-5395-41c9-af90-d7cca7fb6421",
      "status": "queued",
      "image_url": null,
      "width": null,
      "height": null
    }
  ],
  "created_at": "2026-07-30T10:00:00.000Z",
  "updated_at": "2026-07-30T10:00:00.000Z"
}
```

## Retrieve the creatives

Poll the URL in the `Location` response header:

```bash theme={null}
curl https://makelocalads.com/api/v1/campaigns/84b92447-425f-4d2a-9ba1-7d67bf802332 \
  --header "Authorization: Bearer $LOCALADS_API_KEY"
```

Completed creatives appear while the rest continue generating:

```json theme={null}
{
  "id": "84b92447-425f-4d2a-9ba1-7d67bf802332",
  "brand_id": "1423f915-beca-4c53-a5e4-7c8c99537be9",
  "product_id": "a1516a75-9be5-461a-93af-c1896a0a3127",
  "name": "Create a premium campaign focused on",
  "status": "in_progress",
  "requested_creative_count": 10,
  "completed_creative_count": 1,
  "failed_creative_count": 0,
  "creatives": [
    {
      "id": "19025a65-5395-41c9-af90-d7cca7fb6421",
      "status": "completed",
      "image_url": "https://cdn.example.com/campaign-creative.jpg",
      "width": 1024,
      "height": 1024
    }
  ],
  "created_at": "2026-07-30T10:00:00.000Z",
  "updated_at": "2026-07-30T10:02:15.000Z"
}
```

Stop polling when the campaign status is `completed`, `failed`, or `canceled`.
Use backoff between requests rather than polling continuously.

A `completed` campaign may contain an individually failed creative. Check
`failed_creative_count` and the status of each creative before using the
results.

## Not enough credits

When the organization cannot reserve all requested creatives, LocalAds returns
`422 Unprocessable Entity` without creating the campaign:

```json theme={null}
{
  "type": "https://docs.makelocalads.com/errors/insufficient-credits",
  "title": "Not enough credits",
  "status": 422,
  "detail": "Generating 10 creatives needs 10 credits, but you only have 4 remaining.",
  "code": "insufficient_credits",
  "request_id": "83cff1a5-f3ea-42d4-8920-2b2b69ec31de"
}
```
