# Subscription API - Add and Remove Contacts

Use these endpoints to subscribe contacts to a subscription or unsubscribe them in bulk. Both operations are idempotent — adding a contact that is already subscribed, or removing one that is not subscribed, produces no error.

---

## Endpoints

| Method | URL | Description |
|---|---|---|
| POST | `https://e1.envoke.com/v2/subscriptions/{ID}/contacts` | Add contacts to a subscription. |
| DELETE | `https://e1.envoke.com/v2/subscriptions/{ID}/contacts` | Remove contacts from a subscription. |

Replace `{ID}` with the Envoke subscription ID. Authentication is via HTTP Basic Auth using your API ID and API Key. The request body must be JSON.

---

## Request Body

Provide exactly one of `contact_ids` or `contact_emails`. You cannot include both in the same request.

| Field | Type | Description |
|---|---|---|
| `contact_ids` | array of integers | Envoke contact IDs to add or remove. Maximum 1,000 items per request. |
| `contact_emails` | array of strings | Contact email addresses to add or remove. Maximum 1,000 items per request. |

---

## Response

### Success (all contacts found)

```json
{
  "success": true,
  "result_text": "Set to contacts",
  "result_data": {
    "processed": 3
  }
}
```

### Success (some contacts not found)

Contacts that could not be matched are listed in `not_found`. The operation is still considered successful as long as no found contacts failed to update.

```json
{
  "success": true,
  "result_text": "Set to contacts. Some contacts not found",
  "result_data": {
    "processed": 3,
    "not_found": ["ghost@example.com"]
  }
}
```

### Failure

If one or more found contacts failed during the update, `success` is `false` and the failures are listed in `failed`.

```json
{
  "success": false,
  "result_text": "Error setting to contacts",
  "result_data": {
    "processed": 3,
    "failed": [
      { "contact_id": "456", "reason": "error message" }
    ]
  }
}
```

### `result_data` fields

| Field | Type | Description |
|---|---|---|
| `processed` | integer | Total number of input identifiers submitted (found + not found). |
| `not_found` | array | IDs or emails that were not matched to any contact in the account. Only present when at least one was not found. |
| `failed` | array | Contacts that were found but failed during the update. Only present when failures occurred. |

---

## Validation Errors

```json
{
  "success": false,
  "result_text": "Validation failed, see 'result_data' -> 'errors'",
  "result_data": {
    "errors": ["Either 'contact_ids' or 'contact_emails' must be provided"]
  }
}
```

If the request body is completely empty (`{}`), a validation envelope is returned:

```json
{
  "success": false,
  "result_text": "Validation failed, see 'result_data' -> 'errors'",
  "result_data": {
    "errors": ["Request body may not be empty"]
  }
}
```

Common validation errors (returned when a non-empty body is provided but is missing or invalid):

| Error | Cause |
|---|---|
| `Either 'contact_ids' or 'contact_emails' must be provided` | Body was provided but contained neither field. |
| `Provide either 'contact_ids' or 'contact_emails', not both` | Both fields were included. |
| `The field 'contact_ids' must be an array` | `contact_ids` was not an array. |
| `The field 'contact_ids' must not be empty` | `contact_ids` was an empty array. |
| `The field 'contact_ids' may not contain more than 1000 items` | More than 1,000 IDs were submitted. |
| `The field 'contact_emails' must be an array` | `contact_emails` was not an array. |
| `The field 'contact_emails' must not be empty` | `contact_emails` was an empty array. |
| `The field 'contact_emails' may not contain more than 1000 items` | More than 1,000 emails were submitted. |
| `Item with id '{id}' not found` | The subscription ID in the URL does not match any subscription in your account. |

---

## Examples

### Add contacts by ID

```bash
curl -X POST -gs \
  -u "$API_ID:$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contact_ids": [101, 102, 103]}' \
  "https://e1.envoke.com/v2/subscriptions/12/contacts"
```

### Add contacts by email

```bash
curl -X POST -gs \
  -u "$API_ID:$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contact_emails": ["alice@example.com", "bob@example.com"]}' \
  "https://e1.envoke.com/v2/subscriptions/12/contacts"
```

### Remove contacts by ID

```bash
curl -X DELETE -gs \
  -u "$API_ID:$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contact_ids": [101, 102]}' \
  "https://e1.envoke.com/v2/subscriptions/12/contacts"
```

### Remove contacts by email

```bash
curl -X DELETE -gs \
  -u "$API_ID:$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contact_emails": ["alice@example.com"]}' \
  "https://e1.envoke.com/v2/subscriptions/12/contacts"
```

---

*Note: The curl examples above are formatted for readability. All requests must use properly encoded URLs.*

*Full reference, OpenAPI description, and Postman collection: [developers.envoke.com](https://developers.envoke.com).*
