# Campaigns and contact lists

## Contact lists

A list holds a phone number and up to six dynamic fields `df1`–`df6` (first name, city, appointment date…).

```bash
curl -X POST https://smsprovider-web.vercel.app/api/v1/lists \
  -H "Authorization: Bearer $BATLER_API_KEY" -H "Content-Type: application/json" \
  -d '{"name": "VIP customers", "contacts": [{"phone": "0501234567", "df1": "Dana"}, {"phone": "0527654321", "df1": "Yossi"}]}'
```

- Invalid numbers are returned in `rejected` with a reason; duplicates are merged.
- Add/remove: `POST` / `DELETE https://smsprovider-web.vercel.app/api/v1/lists/{id}/contacts` (up to 10,000 per call).
- In the portal you can import CSV or Excel with column mapping.

## Sending a campaign

```json
POST https://smsprovider-web.vercel.app/api/v1/campaigns
{
  "list_id": "5b0d2a8e-1d7c-4a35-9a7e-3c1a3b5e9f00",
  "from": "MyBrand",
  "body": "Hi {{df1}}, end of season sale: 20% off! [shop]",
  "links": { "shop": "https://example.com/sale" },
  "unsubscribe": "link",
  "schedule_at": "2026-11-05T09:00:00+02:00"
}
```

- `{{df1}}`…`{{df6}}` are replaced with each contact's value.
- Unsubscribed contacts and blacklisted numbers are filtered automatically; `skip_recent_days` (1–14) skips people messaged recently.
- The cost is reserved upfront (segments × recipients) and returned as `credits_reserved`.
- Cancel before the scheduled time: `POST https://smsprovider-web.vercel.app/api/v1/campaigns/{id}/cancel` — credits are released.

## Links and click tracking

Every link in a message goes through our shortener: write `[link-id]` in the text and pass `links: { "link-id": "https://…" }`. Each recipient gets a unique short link, so you can see who clicked and when (`GET https://smsprovider-web.vercel.app/api/v1/campaigns/{id}/clicks`, webhook `link.clicked`). WhatsApp/iMessage previews and bots are not counted as clicks. The short link (~30 chars) counts toward message length.

## Unsubscribe (required for marketing messages)

| `unsubscribe` | What is added |
| --- | --- |
| `link` | Our short unsubscribe link at the end. Click → one-tap confirmation → the number joins your blacklist |
| `reply` | A "reply to unsubscribe" text — a reply removes the recipient automatically |
| `none` | Nothing (transactional messages only) |

Place the unsubscribe link inside the text with `[unsubscribe]`. A `blacklist.added` event is sent for every opt-out.
