# Get a campaign

> GET /v2/campaigns/{campaignId}

`GET https://api.zavu.dev/v2/campaigns/{campaignId}`

## Parameters

- `campaignId` (path, string, required): Campaign ID. The same ID works as `broadcastId` on /v1.

## Responses

### 200

The campaign.

- `campaign` (object, required): A campaign. The same object as a /v1 broadcast: its `id` works on `/v1/broadcasts/{broadcastId}`.
  - `id` (string, required)
  - `name` (string, required)
  - `status` (string, required): Current status of the campaign. `pending_review`: in the automated content review. `pending_admin_review`: the automated review passed and it waits for a person, which is where every channel but a WhatsApp campaign on an approved template goes. `rejected`: the review refused it; edit it and send again, or escalate. `scheduled` and `sending` follow approval. One of: `draft`, `pending_review`, `pending_admin_review`, `approved`, `rejected`, `escalated`, `rejected_final`, `scheduled`, `sending`, `paused`, `completed`, `cancelled`, `failed`.
  - `channel` (string, required): Broadcast delivery channel. Use 'smart' for per-contact intelligent routing. One of: `smart`, `sms`, `sms_oneway`, `whatsapp`, `telegram`, `email`.
  - `messageType` (string, required): Type of message for broadcast. One of: `text`, `image`, `video`, `audio`, `document`, `template`.
  - `text` (string)
  - `content` (object): Content for non-text broadcast message types.
    - `mediaUrl` (string): URL of the media file.
    - `mediaId` (string): Media ID if already uploaded.
    - `mimeType` (string): MIME type of the media.
    - `filename` (string): Filename for documents.
    - `templateId` (string): Template ID for template messages.
    - `templateVariables` (object): Default body variables (can be overridden per contact). Key them to match the template body: by position (`1`, `2`, ...) for positional templates, or by name (e.g. `customer_name`) for named templates. Zavu detects the template's format and sends the correct payload to Meta. Do not mix positional and named keys.
      - `{key}` (string)
    - `templateButtonVariables` (object): Default button variables for dynamic URL/OTP buttons. Keys are the button index (0, 1, 2). Per-contact values override these.
      - `{key}` (string)
    - `templateHeaderVariables` (object): Default value for a text-header variable, keyed by `1` (can be overridden per contact). If omitted, Zavu resolves the header from `templateVariables` by the header placeholder's name.
      - `{key}` (string)
  - `emailSubject` (string)
  - `totalContacts` (integer, required): Total number of contacts in the broadcast.
  - `pendingCount` (integer)
  - `sendingCount` (integer)
  - `sentCount` (integer): Recipients whose message the provider accepted, without a confirmed delivery yet. Channels that never report delivery keep their recipients here.
  - `deliveredCount` (integer): Recipients with confirmed delivery to the device.
  - `failedCount` (integer)
  - `estimatedCost` (number, nullable): Estimated total cost in USD.
  - `reservedAmount` (number, nullable): Amount reserved from balance in USD.
  - `actualCost` (number, nullable): Actual cost so far in USD.
  - `scheduledAt` (string<date-time>)
  - `startedAt` (string<date-time>)
  - `completedAt` (string<date-time>)
  - `metadata` (object)
    - `{key}` (string)
  - `createdAt` (string<date-time>, required)
  - `updatedAt` (string<date-time>)
  - `reviewResult` (object, nullable): AI content review result.
    - `score` (number): Content safety score from 0.0 to 1.0, where 1.0 is completely safe.
    - `categories` (string[]): Policy categories violated, if any.
    - `reasoning` (string): Explanation of the review decision.
    - `reviewedAt` (string<date-time>)
    - `flaggedContent` (string[], nullable): Problematic text fragments, if any.
  - `reviewAttempts` (integer, nullable): Number of review attempts (max 3).
  - `from` (string, nullable): The address the campaign is sent from, for its `channel` (the sender's first address when `channel` is `smart`).

### 401

Unauthorized.

- `code` (string, required)
- `message` (string, required)
- `details` (object): Machine-readable context. Keys that mean the same thing everywhere: - `errors`: present on every `400 invalid_request` for an invalid body or query parameter, `[{path, message, ...}]`, `path` naming the field (`["to"]`, `["contacts", 2, "recipient"]`, `["limit"]`). - `recommendation`: one sentence saying what to do next. - `dashboardUrl`: the dashboard screen that fixes it. - `connect`: on `409 no_channel`, the channels this project can connect to reach the recipient, each `{type, request, note, available, dashboardUrl?}`; `request` is the exact call (`POST /v2/channels` with its body, or `POST /v2/numbers`), or null for a channel connected from the dashboard (WhatsApp, Instagram, Messenger). `available: false` says why in `note` (one-way SMS closed until business verification is approved). - `address` / `from`: the address the error is about, under the name the request used for it.
  - `errors` (object[])
    - `path` (object[], required)
    - `message` (string, required)
    - `code` (string)

### 404

Campaign not found, or it belongs to another project.

- `code` (string, required)
- `message` (string, required)
- `details` (object): Machine-readable context. Keys that mean the same thing everywhere: - `errors`: present on every `400 invalid_request` for an invalid body or query parameter, `[{path, message, ...}]`, `path` naming the field (`["to"]`, `["contacts", 2, "recipient"]`, `["limit"]`). - `recommendation`: one sentence saying what to do next. - `dashboardUrl`: the dashboard screen that fixes it. - `connect`: on `409 no_channel`, the channels this project can connect to reach the recipient, each `{type, request, note, available, dashboardUrl?}`; `request` is the exact call (`POST /v2/channels` with its body, or `POST /v2/numbers`), or null for a channel connected from the dashboard (WhatsApp, Instagram, Messenger). `available: false` says why in `note` (one-way SMS closed until business verification is approved). - `address` / `from`: the address the error is about, under the name the request used for it.
  - `errors` (object[])
    - `path` (object[], required)
    - `message` (string, required)
    - `code` (string)

## Example

```bash
curl -X GET "https://api.zavu.dev/v2/campaigns/campaign_abc123" \
  -H "Authorization: Bearer $ZAVUDEV_API_KEY"
```

```typescript
import Zavudev from "@zavudev/sdk";

const zavu = new Zavudev({ apiKey: process.env.ZAVUDEV_API_KEY });

const result = await zavu.v2.campaigns.retrieve("campaign_abc123");

console.log(result);
```
