# Campaigns

## List campaigns

`GET /v1/c/{slug}/campaigns` · Scopes: `campaigns:read`

Newest first, each with its numbers. Filter by `status`.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |

### Query parameters

| Field | Type | Required | Notes |
|---|---|---|---|
| `status` | string | no | up to 40 characters |
| `limit` | integer | no | up to 200; at least 1; default `200` |
| `cursor` | string | no | up to 200 characters |

### Request example

```bash
curl -X GET "https://api.donetalk.com/v1/c/demo/campaigns" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "campaigns": [
    {
      "id": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
      "name": "Reativação · outubro",
      "status": "draft",
      "channel": {
        "id": "01a0cccc-0000-7000-8000-000000000002",
        "name": "Captei"
      },
      "template": {
        "id": "01a0cad0-0000-7000-8000-000000000002",
        "name": "reativacao_cupom",
        "category": "marketing"
      },
      "variables": [
        {
          "slot": "body.1",
          "source": "first_name",
          "format": "none",
          "fallback": "tudo bem"
        },
        {
          "slot": "body.2",
          "source": "value.cupom",
          "format": "upper",
          "fallback": ""
        }
      ],
      "buttons": [
        {
          "index": 0,
          "action": "route"
        }
      ],
      "audience": {
        "kind": "contacts",
        "contactIds": [
          "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
          "01a0d05a-3ee3-75bd-9db5-dc9856f079c9"
        ]
      },
      "excludeOpen": true,
      "frequencyDays": 7,
      "startAt": "2026-10-24T12:00:00.000Z",
      "sendWindow": [
        {
          "day": 1,
          "from": "09:00",
          "to": "18:00"
        }
      ],
      "reply": {
        "kind": "team",
        "id": "01a0cb22-89c0-7e02-b96b-3f4731dde701",
        "goal": null
      },
      "successDays": 7,
      "stopRules": {
        "templatePaused": true,
        "qualityLow": true,
        "optoutRate": 0.03,
        "budget": true
      },
      "budgetMicros": null,
      "estimate": {
        "micros": 77824000,
        "currency": "BRL"
      },
      "audienceCount": 1240,
      "header": null,
      "approval": {
        "required": false,
        "requestedTo": null,
        "requestedAt": null,
        "approvedBy": null,
        "approvedAt": null,
        "rejectedReason": null
      },
      "createdBy": null,
      "createdByKind": "api",
      "startedAt": null,
      "paused": null,
      "completedAt": null,
      "createdAt": "2026-10-23T13:02:11.000Z",
      "updatedAt": "2026-10-23T13:02:11.000Z",
      "stats": {
        "audience": 1240,
        "queued": 0,
        "sending": 0,
        "sent": 1216,
        "delivered": 1198,
        "read": 874,
        "failed": 18,
        "skipped": 24,
        "replied": 141,
        "optedOut": 6,
        "successes": 37,
        "costMicros": 77824000,
        "followMicros": 1260000,
        "aiUsdMicros": 0
      }
    }
  ],
  "nextCursor": null
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `422` `validation_failed`
- `429` `rate_limited`

## Create a campaign

`POST /v1/c/{slug}/campaigns` · Scopes: `campaigns:write`

Creates a draft. Nothing is sent until `submit`. The audience is a segment, a filter or a list of contacts: by id (`contactIds`) or by phone (`people`), with each person's own values for the `value.<key>` variables. Each phone becomes a contact, created or updated, which also needs the contacts:write scope.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |

### Request body

| Field | Type | Required | Notes |
|---|---|---|---|
| `name` | string | yes | up to 120 characters |
| `channelId` | string (uuid) | no | null |
| `templateId` | string (uuid) | no | null |
| `variables` | list of object | no | up to 40 |
| `variables[].slot` | string | yes |  |
| `variables[].source` | one of `name`, `first_name`, `phone`, `fixed` · string | yes |  |
| `variables[].value` | string | no | up to 500 characters |
| `variables[].format` | one of `none`, `title`, `upper`, `lower`, `first` | no | default `"none"` |
| `variables[].fallback` | string | no | up to 200 characters; default `""` |
| `buttons` | list of object | no | up to 10 |
| `buttons[].index` | integer | yes | up to 9 |
| `buttons[].action` | one of `route`, `optout`, `none` | yes |  |
| `audience` | object | no | null |
| `audience.kind` | one of `segment` | yes |  |
| `audience.segmentId` | string (uuid) | yes |  |
| `audience.conditions` | list of object | yes | up to 20 |
| `audience.conditions[].field` | string | yes | up to 80 characters |
| `audience.conditions[].op` | one of `eq`, `neq`, `has`, `not_has`, `contains`, `empty`, `not_empty`, `gt`, `lt`, `none` | yes |  |
| `audience.conditions[].value` | string · number · boolean · one of `null` | no |  |
| `audience.contactIds` | list of string (uuid) | no | up to 20000; default `[]` |
| `audience.people` | list of object | no | up to 20000 |
| `audience.people[].phone` | string | yes | up to 40 characters |
| `audience.people[].name` | string | no | up to 200 characters |
| `audience.people[].fields` | object | no |  |
| `audience.people[].tags` | list of string | no | up to 20 |
| `audience.people[].values` | object | no |  |
| `audience.values` | object | no |  |
| `excludeOpen` | boolean | no |  |
| `frequencyDays` | integer | no | up to 90; null |
| `startAt` | string (date-time) | no | null |
| `sendWindow` | list of object | no | up to 14 |
| `sendWindow[].day` | integer | yes | up to 7; at least 1 |
| `sendWindow[].from` | string | yes |  |
| `sendWindow[].to` | string | yes |  |
| `reply` | object | no |  |
| `reply.kind` | one of `team`, `flow`, `assistant` | no | default `"team"` |
| `reply.id` | string (uuid) | no | default `null`; null |
| `reply.goal` | string | no | up to 200 characters; default `null`; null |
| `successDays` | integer | no | up to 60; at least 1 |
| `stopRules` | object | no |  |
| `stopRules.templatePaused` | boolean | no | default `true` |
| `stopRules.qualityLow` | boolean | no | default `true` |
| `stopRules.optoutRate` | number | no | up to 0.5; at least 0.005; default `0.03`; null |
| `stopRules.budget` | boolean | no | default `true` |
| `budgetMicros` | integer | no | up to 1000000000000000; null |

### Request example

```bash
curl -X POST "https://api.donetalk.com/v1/c/demo/campaigns" \
  -H "Authorization: Bearer $DONETALK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Reativação · outubro",
  "channelId": "01a0cccc-0000-7000-8000-000000000002",
  "templateId": "01a0cad0-0000-7000-8000-000000000002",
  "variables": [
    {
      "slot": "body.1",
      "source": "first_name",
      "fallback": "tudo bem"
    },
    {
      "slot": "body.2",
      "source": "value.cupom",
      "format": "upper"
    }
  ],
  "buttons": [
    {
      "index": 0,
      "action": "route"
    }
  ],
  "audience": {
    "kind": "contacts",
    "people": [
      {
        "phone": "+5548999990001",
        "name": "Ana Souza",
        "values": {
          "cupom": "ana10"
        }
      },
      {
        "phone": "+5548999990002",
        "name": "Bruno Lima",
        "values": {
          "cupom": "bru15"
        }
      }
    ]
  },
  "reply": {
    "kind": "team",
    "id": "01a0cb22-89c0-7e02-b96b-3f4731dde701"
  },
  "startAt": "2026-10-24T12:00:00.000Z"
}'
```

### Response 201

```json
{
  "campaign": {
    "id": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
    "name": "Reativação · outubro",
    "status": "draft",
    "channel": {
      "id": "01a0cccc-0000-7000-8000-000000000002",
      "name": "Captei"
    },
    "template": {
      "id": "01a0cad0-0000-7000-8000-000000000002",
      "name": "reativacao_cupom",
      "category": "marketing"
    },
    "variables": [
      {
        "slot": "body.1",
        "source": "first_name",
        "format": "none",
        "fallback": "tudo bem"
      },
      {
        "slot": "body.2",
        "source": "value.cupom",
        "format": "upper",
        "fallback": ""
      }
    ],
    "buttons": [
      {
        "index": 0,
        "action": "route"
      }
    ],
    "audience": {
      "kind": "contacts",
      "contactIds": [
        "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
        "01a0d05a-3ee3-75bd-9db5-dc9856f079c9"
      ]
    },
    "excludeOpen": true,
    "frequencyDays": 7,
    "startAt": "2026-10-24T12:00:00.000Z",
    "sendWindow": [
      {
        "day": 1,
        "from": "09:00",
        "to": "18:00"
      }
    ],
    "reply": {
      "kind": "team",
      "id": "01a0cb22-89c0-7e02-b96b-3f4731dde701",
      "goal": null
    },
    "successDays": 7,
    "stopRules": {
      "templatePaused": true,
      "qualityLow": true,
      "optoutRate": 0.03,
      "budget": true
    },
    "budgetMicros": null,
    "estimate": {
      "micros": 77824000,
      "currency": "BRL"
    },
    "audienceCount": 1240,
    "header": null,
    "approval": {
      "required": false,
      "requestedTo": null,
      "requestedAt": null,
      "approvedBy": null,
      "approvedAt": null,
      "rejectedReason": null
    },
    "createdBy": null,
    "createdByKind": "api",
    "startedAt": null,
    "paused": null,
    "completedAt": null,
    "createdAt": "2026-10-23T13:02:11.000Z",
    "updatedAt": "2026-10-23T13:02:11.000Z",
    "stats": {
      "audience": 1240,
      "queued": 0,
      "sending": 0,
      "sent": 1216,
      "delivered": 1198,
      "read": 874,
      "failed": 18,
      "skipped": 24,
      "replied": 141,
      "optedOut": 6,
      "successes": 37,
      "costMicros": 77824000,
      "followMicros": 1260000,
      "aiUsdMicros": 0
    }
  }
}
```

### Possible errors

- `400` `template_other_account`
- `401` `unauthorized`
- `403` `insufficient_scope`
- `422` `validation_failed`
- `429` `rate_limited`

## Get a campaign

`GET /v1/c/{slug}/campaigns/{id}` · Scopes: `campaigns:read`

The campaign with its funnel: sent, delivered, read, replies, failures, successes and cost (in micros: 1,000,000 = 1 unit of currency).

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request example

```bash
curl -X GET "https://api.donetalk.com/v1/c/demo/campaigns/:id" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "campaign": {
    "id": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
    "name": "Reativação · outubro",
    "status": "running",
    "channel": {
      "id": "01a0cccc-0000-7000-8000-000000000002",
      "name": "Captei"
    },
    "template": {
      "id": "01a0cad0-0000-7000-8000-000000000002",
      "name": "reativacao_cupom",
      "category": "marketing"
    },
    "variables": [
      {
        "slot": "body.1",
        "source": "first_name",
        "format": "none",
        "fallback": "tudo bem"
      },
      {
        "slot": "body.2",
        "source": "value.cupom",
        "format": "upper",
        "fallback": ""
      }
    ],
    "buttons": [
      {
        "index": 0,
        "action": "route"
      }
    ],
    "audience": {
      "kind": "contacts",
      "contactIds": [
        "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
        "01a0d05a-3ee3-75bd-9db5-dc9856f079c9"
      ]
    },
    "excludeOpen": true,
    "frequencyDays": 7,
    "startAt": "2026-10-24T12:00:00.000Z",
    "sendWindow": [
      {
        "day": 1,
        "from": "09:00",
        "to": "18:00"
      }
    ],
    "reply": {
      "kind": "team",
      "id": "01a0cb22-89c0-7e02-b96b-3f4731dde701",
      "goal": null
    },
    "successDays": 7,
    "stopRules": {
      "templatePaused": true,
      "qualityLow": true,
      "optoutRate": 0.03,
      "budget": true
    },
    "budgetMicros": null,
    "estimate": {
      "micros": 77824000,
      "currency": "BRL"
    },
    "audienceCount": 1240,
    "header": null,
    "approval": {
      "required": false,
      "requestedTo": null,
      "requestedAt": null,
      "approvedBy": null,
      "approvedAt": null,
      "rejectedReason": null
    },
    "createdBy": null,
    "createdByKind": "api",
    "startedAt": "2026-10-24T12:00:00.000Z",
    "paused": null,
    "completedAt": null,
    "createdAt": "2026-10-23T13:02:11.000Z",
    "updatedAt": "2026-10-23T13:02:11.000Z",
    "stats": {
      "audience": 1240,
      "queued": 0,
      "sending": 0,
      "sent": 1216,
      "delivered": 1198,
      "read": 874,
      "failed": 18,
      "skipped": 24,
      "replied": 141,
      "optedOut": 6,
      "successes": 37,
      "costMicros": 77824000,
      "followMicros": 1260000,
      "aiUsdMicros": 0
    }
  }
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `campaign_not_found`
- `422` `validation_failed`
- `429` `rate_limited`

## Edit a draft

`PATCH /v1/c/{slug}/campaigns/{id}` · Scopes: `campaigns:write`

Only a draft changes. Send only what changes.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request body

| Field | Type | Required | Notes |
|---|---|---|---|
| `name` | string | no | up to 120 characters |
| `channelId` | string (uuid) | no | null |
| `templateId` | string (uuid) | no | null |
| `variables` | list of object | no | up to 40 |
| `variables[].slot` | string | yes |  |
| `variables[].source` | one of `name`, `first_name`, `phone`, `fixed` · string | yes |  |
| `variables[].value` | string | no | up to 500 characters |
| `variables[].format` | one of `none`, `title`, `upper`, `lower`, `first` | no | default `"none"` |
| `variables[].fallback` | string | no | up to 200 characters; default `""` |
| `buttons` | list of object | no | up to 10 |
| `buttons[].index` | integer | yes | up to 9 |
| `buttons[].action` | one of `route`, `optout`, `none` | yes |  |
| `audience` | object | no | null |
| `audience.kind` | one of `segment` | yes |  |
| `audience.segmentId` | string (uuid) | yes |  |
| `audience.conditions` | list of object | yes | up to 20 |
| `audience.conditions[].field` | string | yes | up to 80 characters |
| `audience.conditions[].op` | one of `eq`, `neq`, `has`, `not_has`, `contains`, `empty`, `not_empty`, `gt`, `lt`, `none` | yes |  |
| `audience.conditions[].value` | string · number · boolean · one of `null` | no |  |
| `audience.contactIds` | list of string (uuid) | no | up to 20000; default `[]` |
| `audience.people` | list of object | no | up to 20000 |
| `audience.people[].phone` | string | yes | up to 40 characters |
| `audience.people[].name` | string | no | up to 200 characters |
| `audience.people[].fields` | object | no |  |
| `audience.people[].tags` | list of string | no | up to 20 |
| `audience.people[].values` | object | no |  |
| `audience.values` | object | no |  |
| `excludeOpen` | boolean | no |  |
| `frequencyDays` | integer | no | up to 90; null |
| `startAt` | string (date-time) | no | null |
| `sendWindow` | list of object | no | up to 14 |
| `sendWindow[].day` | integer | yes | up to 7; at least 1 |
| `sendWindow[].from` | string | yes |  |
| `sendWindow[].to` | string | yes |  |
| `reply` | object | no |  |
| `reply.kind` | one of `team`, `flow`, `assistant` | no | default `"team"` |
| `reply.id` | string (uuid) | no | default `null`; null |
| `reply.goal` | string | no | up to 200 characters; default `null`; null |
| `successDays` | integer | no | up to 60; at least 1 |
| `stopRules` | object | no |  |
| `stopRules.templatePaused` | boolean | no | default `true` |
| `stopRules.qualityLow` | boolean | no | default `true` |
| `stopRules.optoutRate` | number | no | up to 0.5; at least 0.005; default `0.03`; null |
| `stopRules.budget` | boolean | no | default `true` |
| `budgetMicros` | integer | no | up to 1000000000000000; null |

### Request example

```bash
curl -X PATCH "https://api.donetalk.com/v1/c/demo/campaigns/:id" \
  -H "Authorization: Bearer $DONETALK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Reativação · outubro (2)",
  "frequencyDays": 7
}'
```

### Response 200

```json
{
  "campaign": {
    "id": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
    "name": "Reativação · outubro",
    "status": "draft",
    "channel": {
      "id": "01a0cccc-0000-7000-8000-000000000002",
      "name": "Captei"
    },
    "template": {
      "id": "01a0cad0-0000-7000-8000-000000000002",
      "name": "reativacao_cupom",
      "category": "marketing"
    },
    "variables": [
      {
        "slot": "body.1",
        "source": "first_name",
        "format": "none",
        "fallback": "tudo bem"
      },
      {
        "slot": "body.2",
        "source": "value.cupom",
        "format": "upper",
        "fallback": ""
      }
    ],
    "buttons": [
      {
        "index": 0,
        "action": "route"
      }
    ],
    "audience": {
      "kind": "contacts",
      "contactIds": [
        "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
        "01a0d05a-3ee3-75bd-9db5-dc9856f079c9"
      ]
    },
    "excludeOpen": true,
    "frequencyDays": 7,
    "startAt": "2026-10-24T12:00:00.000Z",
    "sendWindow": [
      {
        "day": 1,
        "from": "09:00",
        "to": "18:00"
      }
    ],
    "reply": {
      "kind": "team",
      "id": "01a0cb22-89c0-7e02-b96b-3f4731dde701",
      "goal": null
    },
    "successDays": 7,
    "stopRules": {
      "templatePaused": true,
      "qualityLow": true,
      "optoutRate": 0.03,
      "budget": true
    },
    "budgetMicros": null,
    "estimate": {
      "micros": 77824000,
      "currency": "BRL"
    },
    "audienceCount": 1240,
    "header": null,
    "approval": {
      "required": false,
      "requestedTo": null,
      "requestedAt": null,
      "approvedBy": null,
      "approvedAt": null,
      "rejectedReason": null
    },
    "createdBy": null,
    "createdByKind": "api",
    "startedAt": null,
    "paused": null,
    "completedAt": null,
    "createdAt": "2026-10-23T13:02:11.000Z",
    "updatedAt": "2026-10-23T13:02:11.000Z",
    "stats": {
      "audience": 1240,
      "queued": 0,
      "sending": 0,
      "sent": 1216,
      "delivered": 1198,
      "read": 874,
      "failed": 18,
      "skipped": 24,
      "replied": 141,
      "optedOut": 6,
      "successes": 37,
      "costMicros": 77824000,
      "followMicros": 1260000,
      "aiUsdMicros": 0
    }
  }
}
```

### Possible errors

- `400` `template_other_account`
- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `campaign_not_found`
- `409` `campaign_not_editable`
- `422` `validation_failed`
- `429` `rate_limited`

## Delete a campaign

`DELETE /v1/c/{slug}/campaigns/{id}` · Scopes: `campaigns:write`

Drafts, cancelled and completed ones. A sending campaign must be cancelled first.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request example

```bash
curl -X DELETE "https://api.donetalk.com/v1/c/demo/campaigns/:id" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "ok": true
}
```

### Possible errors

- `400` `campaign_wrong_status`
- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `campaign_not_found`
- `422` `validation_failed`
- `429` `rate_limited`

## Duplicate

`POST /v1/c/{slug}/campaigns/{id}/duplicate` · Scopes: `campaigns:write`

A new draft with the same setup and audience.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request example

```bash
curl -X POST "https://api.donetalk.com/v1/c/demo/campaigns/:id/duplicate" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 201

```json
{
  "campaign": {
    "id": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b"
  }
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `campaign_not_found`
- `422` `validation_failed`
- `429` `rate_limited`

## Set the header image or document

`PUT /v1/c/{slug}/campaigns/{id}/header` · Scopes: `campaigns:write`

For templates with a media header: upload the file with `POST /uploads` and pass the `uploadId`.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request body

| Field | Type | Required | Notes |
|---|---|---|---|
| `uploadId` | string (uuid) | yes |  |

### Request example

```bash
curl -X PUT "https://api.donetalk.com/v1/c/demo/campaigns/:id/header" \
  -H "Authorization: Bearer $DONETALK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "uploadId": "01a3d1e2-f3a4-7b5c-8d6e-7f8091a2b3c4"
}'
```

### Response 200

```json
{
  "ok": true
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `campaign_not_found`
- `409` `campaign_not_editable`
- `422` `validation_failed`
- `429` `rate_limited`

## Audience preview

`POST /v1/c/{slug}/campaigns/{id}/audience-preview` · Scopes: `campaigns:read`

How many receive it and how many are left out, by reason: blocked, no WhatsApp, opted out, duplicate, marketing frequency, open conversation.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request example

```bash
curl -X POST "https://api.donetalk.com/v1/c/demo/campaigns/:id/audience-preview" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "found": 1264,
  "excluded": {
    "blocked": 0,
    "no_whatsapp": 2,
    "opted_out": 18,
    "duplicate": 0,
    "frequency": 4,
    "open_conversation": 0
  },
  "openConversations": 3,
  "receive": 1240,
  "samples": [
    {
      "contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
      "name": "Ana Souza",
      "address": "5548999990001"
    }
  ]
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `campaign_not_found`
- `422` `validation_failed`
- `429` `rate_limited`

## Message preview

`POST /v1/c/{slug}/campaigns/{id}/message-preview` · Scopes: `campaigns:read`

How the message reads for five people of the audience, and which variables would be empty.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request example

```bash
curl -X POST "https://api.donetalk.com/v1/c/demo/campaigns/:id/message-preview" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "slots": [
    "body.1",
    "body.2"
  ],
  "quickReplies": [
    {
      "index": 0,
      "text": "Quero o cupom"
    }
  ],
  "samples": [
    {
      "contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
      "name": "Ana Souza",
      "text": "Oi Ana! Seu cupom ANA10 vale até sexta. Quer usar agora?",
      "missing": []
    }
  ]
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `campaign_not_found`
- `422` `validation_failed`
- `429` `rate_limited`

## Review: cost, checks and approval

`POST /v1/c/{slug}/campaigns/{id}/review` · Scopes: `campaigns:read`

The estimated cost (up to), the number's daily limit, the budgets, how many people would miss a variable, and whether the campaign will need approval.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request example

```bash
curl -X POST "https://api.donetalk.com/v1/c/demo/campaigns/:id/review" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "estimate": {
    "currency": "BRL",
    "people": 1240,
    "totalMicros": 77824000,
    "markets": [
      {
        "market": "BR",
        "people": 1240,
        "rateMicros": 62760,
        "micros": 77822400
      }
    ]
  },
  "checks": {
    "templateApproved": true,
    "channelActive": true,
    "quality": "GREEN",
    "dailyLimit": 1000,
    "days": 2,
    "budgets": [],
    "campaignBudgetMicros": null,
    "missingVariables": 0
  },
  "approval": {
    "required": false,
    "approvers": []
  }
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `campaign_not_found`
- `422` `validation_failed`
- `429` `rate_limited`

## Send a test

`POST /v1/c/{slug}/campaigns/{id}/test` · Scopes: `campaigns:write`

Sends the message to one phone (yours), without counting in the campaign's numbers.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request body

| Field | Type | Required | Notes |
|---|---|---|---|
| `phone` | string | yes | up to 40 characters |
| `name` | string | no | up to 200 characters |
| `values` | object | no |  |

### Request example

```bash
curl -X POST "https://api.donetalk.com/v1/c/demo/campaigns/:id/test" \
  -H "Authorization: Bearer $DONETALK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "phone": "+5548999990009",
  "name": "Leo",
  "values": {
    "cupom": "teste10"
  }
}'
```

### Response 200

```json
{
  "ok": true,
  "conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
  "messageId": "01a3c0de-8b22-7c33-9d44-0e55f6677889"
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `campaign_not_found`
- `409` `template_not_approved`
- `422` `validation_failed`
- `429` `rate_limited`

## Start or schedule

`POST /v1/c/{slug}/campaigns/{id}/submit` · Scopes: `campaigns:send`

With a future `startAt` it is scheduled; without, it starts now. If the company's approval rule asks, the campaign waits as `pending_approval` until someone approves it in the app, unless the key has “Start without waiting for approval”.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request body

| Field | Type | Required | Notes |
|---|---|---|---|
| `approverId` | string (uuid) | no | default `null`; null |

### Request example

```bash
curl -X POST "https://api.donetalk.com/v1/c/demo/campaigns/:id/submit" \
  -H "Authorization: Bearer $DONETALK_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```

### Response 200

```json
{
  "status": "scheduled"
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `campaign_not_found`
- `409` `campaign_not_editable`
- `409` `template_not_approved`
- `409` `campaign_audience_empty`
- `422` `validation_failed`
- `429` `rate_limited`

## Pause

`POST /v1/c/{slug}/campaigns/{id}/pause` · Scopes: `campaigns:send`

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request example

```bash
curl -X POST "https://api.donetalk.com/v1/c/demo/campaigns/:id/pause" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "status": "paused"
}
```

### Possible errors

- `400` `campaign_wrong_status`
- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `campaign_not_found`
- `422` `validation_failed`
- `429` `rate_limited`

## Resume

`POST /v1/c/{slug}/campaigns/{id}/resume` · Scopes: `campaigns:send`

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request example

```bash
curl -X POST "https://api.donetalk.com/v1/c/demo/campaigns/:id/resume" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "status": "running"
}
```

### Possible errors

- `400` `campaign_wrong_status`
- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `campaign_not_found`
- `422` `validation_failed`
- `429` `rate_limited`

## Cancel

`POST /v1/c/{slug}/campaigns/{id}/cancel` · Scopes: `campaigns:send`

Stops sending for good. What was sent still counts in the results.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request example

```bash
curl -X POST "https://api.donetalk.com/v1/c/demo/campaigns/:id/cancel" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "status": "cancelled"
}
```

### Possible errors

- `400` `campaign_wrong_status`
- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `campaign_not_found`
- `422` `validation_failed`
- `429` `rate_limited`

## Retry the failures

`POST /v1/c/{slug}/campaigns/{id}/retry` · Scopes: `campaigns:send`

Queues again those who failed: all, or only some contacts or error codes. Failures that cannot succeed (a number without WhatsApp, for example) stay out.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request body

| Field | Type | Required | Notes |
|---|---|---|---|
| `contactIds` | list of string (uuid) | no | up to 20000 |
| `errorCodes` | list of string | no | up to 50 |

### Request example

```bash
curl -X POST "https://api.donetalk.com/v1/c/demo/campaigns/:id/retry" \
  -H "Authorization: Bearer $DONETALK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "errorCodes": [
    "131049"
  ]
}'
```

### Response 200

```json
{
  "requeued": 12
}
```

### Possible errors

- `400` `campaign_wrong_status`
- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `campaign_not_found`
- `422` `validation_failed`
- `429` `rate_limited`

## Recipients, one by one

`GET /v1/c/{slug}/campaigns/{id}/recipients` · Scopes: `campaigns:read`

Each contact with the message's status, the reply, the button tapped and the conversation it opened, with its outcome. `status` filters (`sent`, `delivered`, `read`, `failed`, `skipped`, `replied`, `success`); `format=csv` downloads everything.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Query parameters

| Field | Type | Required | Notes |
|---|---|---|---|
| `status` | string | no | up to 20 characters |
| `limit` | integer | no | up to 500; at least 1; default `100` |
| `offset` | integer | no | default `0` |
| `format` | one of `json`, `csv` | no | default `"json"` |

### Request example

```bash
curl -X GET "https://api.donetalk.com/v1/c/demo/campaigns/:id/recipients" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "recipients": [
    {
      "contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
      "name": "Ana Souza",
      "externalRef": "erp-88213",
      "address": "5548999990001",
      "status": "read",
      "skipReason": null,
      "errorCode": null,
      "sentAt": "2026-10-24T12:00:04.000Z",
      "deliveredAt": "2026-10-24T12:00:06.000Z",
      "readAt": "2026-10-24T12:03:51.000Z",
      "repliedAt": "2026-10-24T12:04:02.000Z",
      "buttonIndex": 0,
      "optedOutAt": null,
      "successAt": null,
      "conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
      "nextAttemptAt": null,
      "conversation": {
        "status": "closed",
        "handler": "human",
        "lastInboundAt": "2026-10-24T12:09:10.000Z",
        "lastMessageAt": "2026-10-24T12:20:41.000Z",
        "lastMessageBy": "member",
        "closedAt": "2026-10-24T12:20:41.000Z",
        "closedBy": "member",
        "outcome": {
          "code": "converted",
          "category": "success",
          "label": {
            "pt-BR": "Venda",
            "en": "Sale",
            "es": "Venta"
          },
          "note": "Fechou o plano anual com o cupom ANA10."
        }
      },
      "tags": [
        {
          "id": "01a12150-3610-7c00-b680-188c2b4c7313",
          "name": {
            "pt-BR": "VIP",
            "en": "VIP",
            "es": "VIP"
          }
        }
      ]
    }
  ]
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `campaign_not_found`
- `422` `validation_failed`
- `429` `rate_limited`

## Failures, buttons and clicks

`GET /v1/c/{slug}/campaigns/{id}/insights` · Scopes: `campaigns:read`

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request example

```bash
curl -X GET "https://api.donetalk.com/v1/c/demo/campaigns/:id/insights" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "failures": [
    {
      "code": "131026",
      "count": 9,
      "waiting": 0
    }
  ],
  "skipped": [
    {
      "reason": "opted_out",
      "count": 18
    }
  ],
  "buttons": [
    {
      "index": 0,
      "text": "Quero o cupom",
      "taps": 96
    }
  ],
  "links": [],
  "perHour": [
    {
      "hour": "2026-10-24T12:00:00.000Z",
      "count": 640
    }
  ]
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `campaign_not_found`
- `422` `validation_failed`
- `429` `rate_limited`

