# Subscribers and segments over the API

> Create, update, tag and unsubscribe subscribers from your own app, run double opt-in, build segments in code, and enroll people in sequences.

Source: https://sendbroadcast.net/university/developers/subscribers-and-segments-api

Most integrations do one thing: keep Broadcast's list in step with your own app. In this lesson you add and update subscribers, run double opt-in from code, build a segment, and put people into a sequence. Use a token with Subscribers, Segments and Sequences permissions, read and write.

## Create a subscriber

Post the subscriber under a `subscriber` key:

```bash
curl -X POST https://broadcast.example.com/api/v1/subscribers.json \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "subscriber": {
      "email": "ada@example.com",
      "first_name": "Ada",
      "tags": ["newsletter"],
      "custom_data": { "plan": "pro" }
    }
  }'
```

Only `email` is required. `custom_data` is a JSON object for anything else you know. Segments, topics and Liquid personalization all read it.

Know three behaviours before you wire this up:

1. Posting an address that already exists is not an error. It returns `201`, clears `unsubscribed_at`, and updates the attributes you sent. Do not call create for someone who unsubscribed unless they asked to come back.
2. The subscriber is set active, unless the address is on a suppression list. A suppressed address stays inactive, and the response carries a warning.
3. `source` defaults to `api_subscription`.

## Create with double opt-in

If the person signs up on your site, let Broadcast confirm the address. Add `"double_opt_in": true` next to the `subscriber` object. Broadcast creates the subscriber with `confirmed_at` null, sends a confirmation email from the channel's default confirmation template, and returns `confirmation_status` and `confirmation_url`.

Pass `confirmation_template_id` to use a different template. An existing confirmed subscriber is returned as it is. An existing unconfirmed one gets a fresh confirmation email.

1. **You POST** With `double_opt_in: true`
2. **Subscriber created** `confirmed_at` is null
3. **Confirmation email** Sent by Broadcast
4. **Person clicks the link**

Double opt-in from code. You only make the first call.

## Update a subscriber

The update endpoint does not use an id in the path. It finds the subscriber by the top-level `email`:

```bash
curl -X PATCH https://broadcast.example.com/api/v1/subscribers.json \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "ada@example.com",
    "custom_data_mode": "merge",
    "subscriber": { "custom_data": { "plan": "enterprise" } }
  }'
```

To change the address, put the new one in `subscriber.email` and keep the old one at the top level.

Warning

`custom_data_mode` defaults to `replace`: Broadcast stores `custom_data` exactly as sent and removes keys you leave out. Send `merge` to change only the keys you send. In merge mode, a `null` value deletes that key. `tags` in an update also replaces the existing tags.

### `custom_data_mode: replace`

The default

- Stored after: `plan` only
- `city` is removed

### `custom_data_mode: merge`

Send this to change one key

- Stored after: `plan` and `city`
- A `null` value deletes a key

The stored data is `plan` and `city`. You send only a new `plan`.

## Tags and status

For tags, prefer the small endpoints over a full update, because they do not replace the whole list:

- `POST /api/v1/subscribers/add_tag.json` with `email` and a `tags` array.
- `DELETE /api/v1/subscribers/remove_tag.json` with the same shape.

Tags are often the cleanest bridge into automation. If a sequence uses the tag `trial-started` as its trigger, adding that tag from your app enrolls the person, with no other call.

For status:

- `POST /api/v1/subscribers/unsubscribe.json` sets `unsubscribed_at` and marks the subscriber inactive. Use it when someone opts out in your app.
- `POST /api/v1/subscribers/deactivate.json` and `activate.json` change the active flag that you control.

For GDPR erasure there is a redact endpoint. It removes personal data and keeps campaign statistics. It cannot be undone.

## Read the list

`GET /api/v1/subscribers.json` takes filters: `is_active`, `source`, `created_after` and `created_before`, `email` (a partial match, such as `gmail.com`), `tags[]` (subscribers with all of them), and `custom_data[plan]=enterprise`. Results are paginated: read `pagination.total_pages` and ask for each `page`.

## Build a segment in code

A segment has groups, and groups have rules, the same structure as the dashboard:

```bash
curl -X POST https://broadcast.example.com/api/v1/segments \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "segment": {
      "name": "Enterprise plan",
      "segment_groups_attributes": [{
        "match_type": "all",
        "segment_rules_attributes": [{
          "field": "custom_data.plan", "operator": "equals",
          "value": "enterprise", "rule_type": "text", "value_type": "string"
        }]
      }]
    }
  }'
```

Custom data fields use the `custom_data.` prefix, and `rule_type` tells Broadcast how to compare the value: `text`, `number`, `date` or `boolean`. `match_type` is `all` or `any`. `GET /api/v1/segments/:id` returns the segment with a paginated list of the subscribers who match it now. The [Segments API](/docs/api-segments) lists every field and operator, with custom data examples for text, numbers, booleans and dates.

### Segment

- `name`

### Group

- `match_type`: `all` or `any`
- Inside `segment_groups_attributes`

### Rule

- `field`, `operator`, `value`
- Inside `segment_rules_attributes`

How the JSON above nests. A segment holds groups, and each group holds rules.

## Enroll in a sequence

`POST /api/v1/sequences/:id/add_subscriber` with a `subscriber` object enrolls the person. If the email does not exist yet, Broadcast creates the subscriber. It returns `201` for a new enrollment, and `200` if the person was already enrolled. `DELETE /api/v1/sequences/:id/remove_subscriber` with `email` takes them out.

## What you learned

- Create is idempotent on email, and it resubscribes an existing address.
- `double_opt_in: true` sends the confirmation email for you.
- Update finds the subscriber by top-level `email`. Use `custom_data_mode: merge` to keep other keys.
- Segments use groups of rules, and sequences take subscribers with `add_subscriber`.

## Quiz
1. What does PATCH /api/v1/subscribers.json use to find the subscriber to update?
   - The subscriber id in the URL
   - The top-level email parameter in the request body (correct)
   - The first tag in the request
   The update endpoint identifies the subscriber by the top-level email, not by an id in the path.
2. You send custom_data with one key in an update. How do you keep the other keys?
   - Send custom_data_mode set to merge (correct)
   - Nothing, keys are always merged
   - Send the request twice
   - Use the add_tag endpoint instead
   The default mode is replace, which removes keys you leave out. merge changes only the keys you send.
3. You POST a subscriber with double_opt_in set to true. What is the result?
   - The subscriber is confirmed at once
   - The request fails until the subscriber clicks a link
   - The subscriber is created unconfirmed and gets a confirmation email (correct)
   Broadcast creates the subscriber with confirmed_at null and sends a confirmation email, using the channel's default confirmation template unless you pass one.
