> For the complete documentation index, see [llms.txt](https://docs.oomus.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.oomus.org/api-reference/campaigns-and-jobs.md).

# Campaigns & Jobs

This section documents the endpoints for managing campaigns and card generation jobs.

**Base URL:** `https://api.oomus.health`\
**Authentication:** All requests require `Authorization: Bearer <TOKEN>`

***

## Campaigns

### POST /campaigns/

Creates a new campaign.

**Request body:**

```json
{
  "name": "Vaccination EPI - Dakar 2026",
  "campaign_type": "vaccination",
  "prefix": "DKR-VAC",
  "language": "fr",
  "template_id": "vaccination",
  "description": "Pilot campaign for Dakar Plateau district"
}
```

| Field           | Type   | Required | Description                         |
| --------------- | ------ | -------- | ----------------------------------- |
| `name`          | string | Yes      | Campaign name (2–200 characters)    |
| `campaign_type` | string | Yes      | Type among supported types          |
| `prefix`        | string | Yes      | Unique 3–8 uppercase character code |
| `language`      | string | Yes      | `fr`, `en`, or `wo`                 |
| `template_id`   | string | Yes      | Card template identifier            |
| `description`   | string | No       | Optional description                |

**201 Created response:**

```json
{
  "id": "camp_01HXYZ456DEF",
  "name": "Vaccination EPI - Dakar 2026",
  "campaign_type": "vaccination",
  "prefix": "DKR-VAC",
  "language": "fr",
  "template_id": "vaccination",
  "status": "draft",
  "total_cards": 0,
  "created_at": "2026-05-15T09:05:00Z",
  "updated_at": "2026-05-15T09:05:00Z"
}
```

**Errors:**

| Code  | Description                                  |
| ----- | -------------------------------------------- |
| `400` | Prefix already used in your organization     |
| `402` | Beneficiary quota exhausted                  |
| `404` | Plan not found or inactive                   |
| `422` | Validation error (missing or invalid fields) |

***

### GET /campaigns/

Returns the list of campaigns for the authenticated account.

**Optional query parameters:**

| Parameter       | Type    | Description                                   |
| --------------- | ------- | --------------------------------------------- |
| `status`        | string  | Filter by status (`draft`, `completed`, etc.) |
| `campaign_type` | string  | Filter by type                                |
| `limit`         | integer | Number of results (default: 20, max: 100)     |
| `offset`        | integer | Offset for pagination                         |

**200 OK response:**

```json
{
  "total": 12,
  "limit": 20,
  "offset": 0,
  "items": [
    {
      "id": "camp_01HXYZ456DEF",
      "name": "Vaccination EPI - Dakar 2026",
      "campaign_type": "vaccination",
      "prefix": "DKR-VAC",
      "status": "completed",
      "total_cards": 1250,
      "created_at": "2026-05-15T09:05:00Z"
    }
  ]
}
```

***

### GET /campaigns/{campaign\_id}

Returns the details of a specific campaign.

**200 OK response:**

```json
{
  "id": "camp_01HXYZ456DEF",
  "name": "Vaccination EPI - Dakar 2026",
  "campaign_type": "vaccination",
  "prefix": "DKR-VAC",
  "language": "fr",
  "template_id": "vaccination",
  "status": "completed",
  "total_cards": 1250,
  "jobs": [
    {
      "job_id": "job_01HXYZ789GHI",
      "status": "completed",
      "cards_generated": 1250,
      "created_at": "2026-05-15T09:10:00Z"
    }
  ],
  "created_at": "2026-05-15T09:05:00Z",
  "updated_at": "2026-05-15T09:30:00Z"
}
```

***

### PATCH /campaigns/{campaign\_id}

Updates an existing campaign (name, description only — the prefix and type are immutable).

**Request body:**

```json
{
  "name": "Vaccination EPI - Dakar 2026 (Revised)",
  "description": "Revised version after field validation"
}
```

***

### DELETE /campaigns/{campaign\_id}

Archives a campaign (does not delete generated cards).

**204 No Content response**

***

## Generation jobs

### POST /campaigns/{campaign\_id}/jobs

Starts a new card generation job.

**Request body:**

```json
{
  "beneficiaries": [
    {
      "first_name": "Aminata",
      "last_name": "Diallo",
      "date_of_birth": "2020-03-15",
      "beneficiary_id": "BEN-001",
      "phone_number": "+221771234567"
    },
    {
      "first_name": "Moussa",
      "last_name": "Sow",
      "date_of_birth": "2019-07-22",
      "beneficiary_id": "BEN-002"
    }
  ],
  "dpi": 300,
  "include_mpi_id": true
}
```

| Field            | Type    | Required | Description                                            |
| ---------------- | ------- | -------- | ------------------------------------------------------ |
| `beneficiaries`  | array   | Yes      | List of beneficiaries (max 10,000 per job)             |
| `dpi`            | integer | No       | 300, 450, or 600 (default: 300)                        |
| `include_mpi_id` | boolean | No       | Include the MPI identifier on the card (default: true) |

**202 Accepted response:**

```json
{
  "job_id": "job_01HXYZ789GHI",
  "campaign_id": "camp_01HXYZ456DEF",
  "status": "pending",
  "total_cards": 2,
  "quota_consumed": 2,
  "created_at": "2026-05-15T09:10:00Z"
}
```

**Errors:**

| Code  | Description                                                 |
| ----- | ----------------------------------------------------------- |
| `402` | Insufficient beneficiary quota for this generation          |
| `404` | Campaign not found or plan not found                        |
| `422` | Invalid beneficiary data (missing fields, incorrect format) |

***

### GET /jobs/{job\_id}

Returns the status and progress of a job.

**200 OK response (job in progress):**

```json
{
  "job_id": "job_01HXYZ789GHI",
  "campaign_id": "camp_01HXYZ456DEF",
  "status": "generating",
  "progress": 65,
  "cards_generated": 1,
  "total_cards": 2,
  "eta_seconds": 12,
  "started_at": "2026-05-15T09:10:05Z"
}
```

**200 OK response (job completed):**

```json
{
  "job_id": "job_01HXYZ789GHI",
  "campaign_id": "camp_01HXYZ456DEF",
  "status": "completed",
  "progress": 100,
  "cards_generated": 2,
  "total_cards": 2,
  "artifacts": {
    "pdf_url": "https://api.oomus.health/jobs/job_01HXYZ789GHI/download/pdf",
    "zip_url": "https://api.oomus.health/jobs/job_01HXYZ789GHI/download/zip",
    "verification_portal_url": "https://api.oomus.health/jobs/job_01HXYZ789GHI/download/portal",
    "manifest_url": "https://api.oomus.health/jobs/job_01HXYZ789GHI/download/manifest"
  },
  "started_at": "2026-05-15T09:10:05Z",
  "completed_at": "2026-05-15T09:10:48Z"
}
```

**200 OK response (job failed):**

```json
{
  "job_id": "job_01HXYZ789GHI",
  "status": "failed",
  "error": "Generation failed: incomplete template data",
  "quota_refunded": 2,
  "failed_at": "2026-05-15T09:10:30Z"
}
```

***

### GET /jobs/{job\_id}/download/{artifact}

Downloads a generation artifact.

Values of `{artifact}` : `pdf`, `zip`, `portal`, `manifest`

**200 OK response:** Binary file content with appropriate Content-Type and Content-Disposition headers.

***

### WebSocket — Real-time progress

Connect to the WebSocket to receive live updates without polling:

```
wss://api.oomus.health/ws/jobs/{job_id}?token={access_token}
```

**Events received:**

```json
{
  "event": "progress",
  "job_id": "job_01HXYZ789GHI",
  "status": "generating",
  "progress": 45,
  "cards_generated": 1,
  "total_cards": 2,
  "eta_seconds": 18
}
```

```json
{
  "event": "completed",
  "job_id": "job_01HXYZ789GHI",
  "status": "completed",
  "progress": 100,
  "cards_generated": 2,
  "artifacts": { ... }
}
```

```json
{
  "event": "failed",
  "job_id": "job_01HXYZ789GHI",
  "status": "failed",
  "error": "Error during generation",
  "quota_refunded": 2
}
```

***

## Complete example: start a generation and track its status

```bash
# Step 1: Authenticate
TOKEN=$(curl -s -X POST https://api.oomus.health/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "contact@votre-programme.sn", "password": "MonMDP!"}' \
  | jq -r '.access_token')

# Step 2: Create the campaign
CAMP_ID=$(curl -s -X POST https://api.oomus.health/campaigns/ \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Test Generation",
    "campaign_type": "vaccination",
    "prefix": "TEST01",
    "language": "fr",
    "template_id": "vaccination"
  }' | jq -r '.id')

# Step 3: Start the job
JOB_ID=$(curl -s -X POST https://api.oomus.health/campaigns/$CAMP_ID/jobs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "beneficiaries": [
      {"first_name": "Test", "last_name": "User", "beneficiary_id": "T001"}
    ],
    "dpi": 300,
    "include_mpi_id": true
  }' | jq -r '.job_id')

echo "Job launched: $JOB_ID"

# Step 4: Polling until completion
while true; do
  STATUS=$(curl -s https://api.oomus.health/jobs/$JOB_ID \
    -H "Authorization: Bearer $TOKEN" | jq -r '.status')
  echo "Status: $STATUS"
  if [ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ]; then
    break
  fi
  sleep 5
done

# Step 5: Download the ZIP
curl -X GET https://api.oomus.health/jobs/$JOB_ID/download/zip \
  -H "Authorization: Bearer $TOKEN" \
  -o "cards.zip"
```

***

## Next steps

* [Billing](/api-reference/billing.md) — Manage your quota
* [DHIS2](/api-reference/dhis2.md) — Generate from DHIS2
* [Authentication](/api-reference/authentication.md) — Token management


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.oomus.org/api-reference/campaigns-and-jobs.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
