# Campaigns

A campaign is a message sequence that Telegram accounts send to contacts on a schedule.

Base URL: https://api.melioralab.io/v1. Pass the key in the `Authorization: Bearer mel_live_...` header.

Endpoints:

- `GET /v1/campaigns`: List campaigns
- `GET /v1/campaigns/{id}`: Retrieve a campaign

## The Campaign object

Campaign: a sequence of messages that Telegram accounts send to contacts.

| Field | Type | Description |
|---|---|---|
| `object` | string | Object type, always `campaign`. |
| `id` | string (uuid) | Campaign ID. |
| `workspace_id` | string (uuid) | Workspace the campaign belongs to. |
| `name` | string | Campaign name. |
| `status` | string | Campaign status. An unknown value is returned as `unknown`. Values: `draft`, `scheduled`, `active`, `paused`, `stopped`, `completed`, `archived`, `launching`, `failed`, `paused_no_credits`, `unknown`. |
| `first_message_mode` | string | Where the first message comes from. Always `template` in v1: from the campaign template. |
| `accepts_api_leads` | boolean | Whether the campaign accepts contacts through the API. Always `false` in v1. |
| `reason` | object | Why the campaign is not sending messages right now, if known. |
| `reason.reason_code` | string | Reason code. Values: `none`, `schedule_window`, `daily_limit`, `queue_pending`, `telegram_wait`, `account_unavailable`, `account_restricted`, `campaign_paused`, `subscription_inactive`, `manual_hold`, `automation_stopped`, `service_unavailable`, `unknown`. |
| `reason.reason_observed_at` | string (date-time) or null | When the reason was recorded. `null` if unknown. |
| `reason.next_attempt_at` | string (date-time) or null | When the next attempt is expected. `null` if the time is unknown. |
| `reason.requires_customer_action` | boolean or null | Whether someone needs to act in Meliora for sending to resume. `null` if unknown. |
| `created_at` | string (date-time) | When the campaign was created. |
| `observed_at` | string (date-time) | Time the server read the data. |

Example:

```json
{
  "object": "campaign",
  "id": "4d8b2f73-6e1a-4c95-b7d0-8a3f5e2c9b14",
  "workspace_id": "3f6a9d21-8b4c-4e7f-a102-5c9e8d7b6a43",
  "name": "Example campaign",
  "status": "active",
  "first_message_mode": "template",
  "accepts_api_leads": false,
  "reason": {
    "reason_code": "none",
    "reason_observed_at": null,
    "next_attempt_at": null,
    "requires_customer_action": null
  },
  "created_at": "2026-10-20T08:00:00.000Z",
  "observed_at": "2026-10-27T09:15:42.000Z"
}
```

## List campaigns

`GET /v1/campaigns`

Campaigns in the key's scope, oldest first by `created_at`.

Permission: `campaigns:read`. Request weight: 2.

### Parameters

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `limit` | query | integer | no | Number of objects to return per page. From 1 to 100. Defaults to `50`. |
| `cursor` | query | string | no | The `next_cursor` value from the previous response. Other filters must match the first request. |
| `workspace_id` | query | string (uuid) | no | Only objects in this workspace. |
| `status` | query | string | no | Only campaigns with this status. Values: `draft`, `scheduled`, `active`, `paused`, `stopped`, `completed`, `archived`, `launching`, `failed`, `paused_no_credits`, `unknown`. |

### Response

A list: `object`, `data`, `has_more`, `next_cursor`. Pagination: https://docs.melioralab.io/en/md/pagination.md

### Endpoint-specific errors

- `cursor_mismatch` (400): The cursor is corrupted, was issued for a different route or filters, or the key's permissions and scope have changed.
- `scope_required` (403): The key does not have permission for this read. Texts also require "Message text" to be enabled.
- `not_found` (404): The object was not found or is outside the key's scope. An unknown path also returns 404.
- `cursor_expired` (410): The cursor expired: 15 minutes for lists, 30 days for the event feed.

Common errors: https://docs.melioralab.io/en/md/errors.md

### Example request

```bash
curl -G https://api.melioralab.io/v1/campaigns \
  -H "Authorization: Bearer $MELIORA_API_KEY" \
  -d workspace_id=3f6a9d21-8b4c-4e7f-a102-5c9e8d7b6a43 \
  -d status=active
```

### Example response

```json
{
  "object": "list",
  "data": [
    {
      "object": "campaign",
      "id": "4d8b2f73-6e1a-4c95-b7d0-8a3f5e2c9b14",
      "workspace_id": "3f6a9d21-8b4c-4e7f-a102-5c9e8d7b6a43",
      "name": "Example campaign",
      "status": "active",
      "first_message_mode": "template",
      "accepts_api_leads": false,
      "reason": {
        "reason_code": "none",
        "reason_observed_at": null,
        "next_attempt_at": null,
        "requires_customer_action": null
      },
      "created_at": "2026-10-20T08:00:00.000Z",
      "observed_at": "2026-10-27T09:15:42.000Z"
    },
    {
      "object": "campaign",
      "id": "6e3a9c15-2b7d-4f80-9a64-3c1d8e5f7b29",
      "workspace_id": "3f6a9d21-8b4c-4e7f-a102-5c9e8d7b6a43",
      "name": "Follow-up",
      "status": "paused",
      "first_message_mode": "template",
      "accepts_api_leads": false,
      "reason": {
        "reason_code": "campaign_paused",
        "reason_observed_at": "2026-10-25T16:40:00.000Z",
        "next_attempt_at": null,
        "requires_customer_action": true
      },
      "created_at": "2026-10-22T11:15:00.000Z",
      "observed_at": "2026-10-27T09:15:42.000Z"
    }
  ],
  "has_more": true,
  "next_cursor": "v1.k1.Qm9hcmRfMWZ4.c3RyaWN0bHlfb3BhcXVl.dGFnX2V4YW1wbGU.bWFjX2V4YW1wbGVfdmFsdWU"
}
```

## Retrieve a campaign

`GET /v1/campaigns/{id}`

A single campaign by ID. A campaign outside the key's scope returns 404, as if it did not exist.

Permission: `campaigns:read`. Request weight: 1.

### Parameters

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string (uuid) | yes | Campaign ID. |

### Response

Returns a `Campaign` object.

### Endpoint-specific errors

- `scope_required` (403): The key does not have permission for this read. Texts also require "Message text" to be enabled.
- `not_found` (404): The object was not found or is outside the key's scope. An unknown path also returns 404.

Common errors: https://docs.melioralab.io/en/md/errors.md

### Example request

```bash
curl https://api.melioralab.io/v1/campaigns/4d8b2f73-6e1a-4c95-b7d0-8a3f5e2c9b14 \
  -H "Authorization: Bearer $MELIORA_API_KEY"
```

### Example response

```json
{
  "object": "campaign",
  "id": "4d8b2f73-6e1a-4c95-b7d0-8a3f5e2c9b14",
  "workspace_id": "3f6a9d21-8b4c-4e7f-a102-5c9e8d7b6a43",
  "name": "Example campaign",
  "status": "active",
  "first_message_mode": "template",
  "accepts_api_leads": false,
  "reason": {
    "reason_code": "none",
    "reason_observed_at": null,
    "next_attempt_at": null,
    "requires_customer_action": null
  },
  "created_at": "2026-10-20T08:00:00.000Z",
  "observed_at": "2026-10-27T09:15:42.000Z"
}
```
