---
title: "Opt contacts out of a topic"
description: "Opt many contacts out of this topic in one call, as a background job: the contacts you list (contact_ids or emails, up to 1,000, each a contact of this workspace) or every member of a segment (segment_id, however many; also needs segments:read). `POST /api/v1/email/topics/{id}/opt-out`"
url: https://www.unitpost.com/docs/email/post-email-topics-id-opt-out
section: "Email API reference"
updated: 2026-10-13
---
# Opt contacts out of a topic

`POST /api/v1/email/topics/{id}/opt-out`

Opt many contacts out of this topic in one call, as a background job: the contacts you list (`contact_ids` or `emails`, up to 1,000, each a contact of this workspace) or every member of a segment (`segment_id`, however many; also needs `segments:read`). Send exactly one. Each contact is opted out as [Set a contact's topic preference](https://www.unitpost.com/docs/email/post-contacts-id-topics) would: one that was subscribed gets a `topic.unsubscribed` webhook and an activity row naming your key; one already opted out is left as it is, with no webhook. Suppressions and other topics are untouched, and there is no bulk opt-in. Listed contacts are checked first: the first that isn't one of yours is a `404` naming it (`details`), and nothing starts. The answer is the job (`202`, `Location`); follow it with [Retrieve a job](https://www.unitpost.com/docs/platform/get-jobs-id). Pass an `Idempotency-Key` so a retry answers the same job instead of starting another. Requires the `topics:write` capability.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | — |
| `Idempotency-Key` | header | string | no | Any unique string (1–256 characters, e.g. a UUID). Retrying with the same key and the same body within 24 hours returns the first result instead of sending again; the same key with a different body is `409 invalid_idempotent_request`, and one still in flight is `409 concurrent_idempotent_requests`. |

## Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `contact_ids` | string[] | no | Contacts of this workspace (`con_…`), up to 1,000. |
| `emails` | string[] | no | Contacts of this workspace by email address, up to 1,000. |
| `segment_id` | string | no | Every member of this segment (`seg_…`), however many. Also needs `segments:read`. |

## Response fields (202)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `object` | string | yes | — |
| `id` | string | yes | — |
| `kind` | string | yes | — |
| `status` | enum | yes | One of: `QUEUED`, `RUNNING`, `COMPLETED`, `FAILED`, `CANCELED`. |
| `total` | integer \| null | yes | — |
| `processed` | integer | yes | — |
| `failed` | integer | yes | — |
| `error` | string \| null | yes | — |
| `created_at` | string | yes | — |
| `completed_at` | string \| null | yes | — |

## Responses

| Status | Description |
| --- | --- |
| 202 | The opt-out job (`Location` names it). |
| 400 | The body isn't JSON, or the `Idempotency-Key` header is not 1–256 characters. |
| 401 | Missing or invalid API key. |
| 403 | Insufficient scope (`segment_id` also needs `segments:read`). |
| 404 | Topic not found; or a listed contact or the segment isn't in this workspace (`details` names it). |
| 409 | Idempotency conflict: the same key with a different body or topic, or one still in flight; or `job_in_progress`: five opt-outs are already running in this workspace (follow them with `GET /jobs`). |
| 422 | Not exactly one of `contact_ids`, `emails` and `segment_id`, more than 1,000 listed, or an unknown key. |
| 429 | Too many opt-outs started this minute (`Retry-After`). |
| 502 | `engine_unavailable`: the job couldn't be started; nothing was opted out. Retry. |

## Example request

```bash
curl -X POST 'https://www.unitpost.com/api/v1/email/topics/top_123/opt-out' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'User-Agent: my-app/1.0' \
  -H 'Content-Type: application/json' \
  -d '{ }'
```

## Example response (202)

```json
{
  "object": "job",
  "id": "id_123",
  "kind": "string",
  "status": "QUEUED",
  "total": 1,
  "processed": 0,
  "failed": 0,
  "error": "string",
  "created_at": "2026-01-01T00:00:00.000Z",
  "completed_at": "2026-01-01T00:00:00.000Z"
}
```

## Links

- HTML reference (with Node.js, Python, Ruby, PHP, Laravel, Go, Java, Rust, .NET and CLI examples): https://www.unitpost.com/docs/email/post-email-topics-id-opt-out
- OpenAPI 3.1 (full schemas): https://www.unitpost.com/api/v1/openapi.json
