# Lists and campaigns API

Broadcasts use lists + a campaign job on the `broadcast` route.

## Lists

```bash
curl -sS -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Newsletter"}' \
  "$BASE/api/practices/$PRACTICE_ID/lists"

curl -sS -H "Authorization: Bearer $TOKEN" \
  "$BASE/api/practices/$PRACTICE_ID/lists"
```

List payloads include `subscriber_count` and `active_count`.

## Subscribers

```bash
# DOI (default) — pending + confirm email
curl -sS -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email":"a@example.com"}' \
  "$BASE/api/practices/$PRACTICE_ID/lists/$LIST_ID/subscribers"

# already-consented import
curl -sS -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email":"a@example.com","status":"active"}' \
  "$BASE/api/practices/$PRACTICE_ID/lists/$LIST_ID/subscribers"

curl -sS -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"emails":["a@example.com","b@example.com"]}' \
  "$BASE/api/practices/$PRACTICE_ID/lists/$LIST_ID/subscribers/import"

curl -sS -H "Authorization: Bearer $TOKEN" \
  "$BASE/api/practices/$PRACTICE_ID/lists/$LIST_ID/subscribers"

curl -sS -X DELETE -H "Authorization: Bearer $TOKEN" \
  "$BASE/api/practices/$PRACTICE_ID/lists/$LIST_ID/subscribers/$SUB_ID"
```

Without `status: active` / `skip_doi`, create starts double opt-in. Public confirm: `GET /api/public/confirm?token=…`.

Public subscribe (`POST /api/public/subscribe`) also starts DOI and does **not** return `confirm_url`.

## Campaigns

```bash
curl -sS -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "list_id": "'"$LIST_ID"'",
    "name": "April newsletter",
    "subject": "Praxis news",
    "text_body": "Hello",
    "html_body": "<p>Hello</p>",
    "route": "broadcast"
  }' \
  "$BASE/api/practices/$PRACTICE_ID/campaigns"

curl -sS -H "Authorization: Bearer $TOKEN" \
  "$BASE/api/practices/$PRACTICE_ID/campaigns"
```

The create response includes the campaign ledger row and a `job_id`. Campaigns require marketing eligibility (DKIM, warm-up, Impressum, consent).
