Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: ClickFunnels Contacts::Unsubscribe Action API
termsOfService: https://www.clickfunnels.com/terms-of-service
contact:
name: ClickFunnels API Team
url: https://developers.myclickfunnels.com
x-logo:
url: https://statics.myclickfunnels.com/image/1126065/file/31edf05760fafe41a82f16a668ab251f.png
description: 'The ClickFunnels REST API that powers webhooks, native integrations, and Zapier lets you manage your ClickFunnels data, automate your workflows, and recreate ClickFunnels functionality in your own apps.
### For AI agents
This document is the catalogue: every operation ClickFunnels exposes over REST is described here, with a unique operationId, typed schemas, and the scopes it needs. It is served from `/openapi.json`, `/openapi.yaml`, `/api/openapi.{json,yaml}`, and `/api/v2/openapi.{json,yaml}` on the accounts host.
Three things it does not describe, each one request away:
- MCP server: the app-native Model Context Protocol server (Streamable HTTP, OAuth 2.1 with PKCE). Prefer it over raw REST when your client supports MCP - it describes itself at runtime.
- Skill guides, also as an Agent Skills index: one task guide per job (pages, blogs, products, orders, workflows, emails, courses, stats, external SDK pages). Read the guide that matches your job before your first write. llms.txt covers when to use ClickFunnels at all, how to get credentials, and how to behave around rate limits.
- Protected resource metadata (RFC 9728) and authorization server metadata (RFC 8414): the scope vocabulary and the OAuth endpoints. Dynamic client registration is for MCP clients only.
On ClickFunnels-owned API hosts (`myclickfunnels.com` and its subdomains), the OpenAPI specification responses and API authentication failures (401, or 403 for insufficient scope) carry those links in an RFC 8288 `Link` header, so clients can discover the documentation and authentication metadata from those responses. Requests sent through a customer''s custom domain keep the Bearer challenge but omit those discovery pointers.'
license:
name: MIT
url: https://opensource.org/licenses/MIT
version: 2.0.0
servers:
- url: https://{subdomain}.myclickfunnels.com/api/v2
description: ClickFunnels API
variables:
subdomain:
default: myworkspace
security:
- BearerAuth: []
- OAuth2: []
tags:
- name: Contacts::UnsubscribeAction
description: '> Bulk-unsubscribe contacts from email
An Unsubscribe Action marks an entire audience of contacts as unsubscribed from email in a single async operation.
**Target selection** — supply exactly one of:
- `stable_id` — a URL-encoded Refine `stable_id` token.
- `stored_filter_id` — the `id` or `public_id` of a saved `Refine::StoredFilter` (ContactsFilter). Also accepted as `filter_id`.
- `target_ids` — an explicit array of contact public IDs.
- `target_all` — `true` to target every contact in the workspace.
**Progress tracking** — after creating an Unsubscribe Action, poll it with `GET /api/v2/contacts/unsubscribe_actions/{id}`.'
paths:
/workspaces/{workspace_id}/contacts/unsubscribe_actions:
get:
tags:
- Contacts::UnsubscribeAction
summary: List Unsubscribe Actions
description: List all Contact Unsubscribe Actions for your workspace
operationId: listContactsUnsubscribeActions
parameters:
- name: workspace_id
in: path
required: true
schema:
type: string
- $ref: '#/components/parameters/after'
- $ref: '#/components/parameters/per_page'
- $ref: '#/components/parameters/sort_order'
- $ref: '#/components/parameters/sort_property'
responses:
'200':
description: OK
headers:
Pagination-Next:
$ref: '#/components/headers/PaginationNext'
Link:
$ref: '#/components/headers/Link'
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/ContactsUnsubscribeActionAttributes'
example:
- id: 1
public_id: cD5eF6
workspace_id: 42000
filter_id: 7
target_all: false
target_ids: []
target_count: 300
performed_count: 300
created_by_id: 5
approved_by_id: null
scheduled_for: null
started_at: '2025-01-01T00:01:00.000Z'
completed_at: '2025-01-01T00:02:30.000Z'
created_at: '2025-01-01T00:00:00.000Z'
updated_at: '2025-01-01T00:02:30.000Z'
- id: 2
public_id: gH7iJ8
workspace_id: 42000
filter_id: null
target_all: false
target_ids:
- cust_abc
- cust_def
target_count: 2
performed_count: 0
created_by_id: 5
approved_by_id: null
scheduled_for: null
started_at: null
completed_at: null
created_at: '2025-01-02T00:00:00.000Z'
updated_at: '2025-01-02T00:00:00.000Z'
'401':
description: Unauthorized
content:
application/json:
schema:
type: object
properties:
error:
type: string
hint:
type:
- string
- 'null'
description: 'The next step for the caller: how to authenticate, which scope was missing, or where the route list lives. Always present, and null when this error has no next step to offer.'
example:
error: API key missing or invalid
hint: 'Send the token as `Authorization: Bearer <token>`. Create one under Account > Team > Platform Applications (a workspace API key), or obtain one with OAuth 2.1; both use the same scopes. See https://developers.myclickfunnels.com/docs/authentication, or append .md to that URL for markdown.'
'404':
description: Not Found
content:
application/json:
schema:
type: object
properties:
error:
type: string
description: Not found - This usually happens when you try to access a record that does not exist in your account. It can also happen when the provided parent record is missing, e.g. you have put in a non-existent Workspaces parent ID.
hint:
type:
- string
- 'null'
description: 'The next step for the caller: how to authenticate, which scope was missing, or where the route list lives. Always present, and null when this error has no next step to offer.'
example:
error: 'Not found: Record missing'
hint: null
'422':
$ref: '#/components/responses/InvalidPageSize'
post:
tags:
- Contacts::UnsubscribeAction
summary: Create Unsubscribe Action
description: 'Bulk-unsubscribe a collection of contacts from email. The action runs asynchronously — poll the returned record with `GET /api/v2/contacts/unsubscribe_actions/{id}` to track progress via `target_count` and `performed_count`.
Exactly one target selection must be supplied: `stable_id`, `stored_filter_id` (alias `filter_id`), `target_ids`, or `target_all`. Returns 422 if none is provided or if the supplied value is invalid.'
operationId: createContactsUnsubscribeActions
parameters:
- name: workspace_id
in: path
required: true
schema:
type: string
requestBody:
description: Information about a new Unsubscribe Action
required: true
content:
application/json:
schema:
type: object
properties:
contacts_unsubscribe_action:
type: object
$ref: '#/components/schemas/ContactsUnsubscribeActionParameters'
example:
contacts_unsubscribe_action:
stored_filter_id: '7'
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/ContactsUnsubscribeActionAttributes'
example:
id: 3
public_id: kL9mN0
workspace_id: 42000
filter_id: 7
target_all: false
target_ids: []
target_count: null
performed_count: 0
created_by_id: 5
approved_by_id: null
scheduled_for: null
started_at: null
completed_at: null
created_at: '2025-01-03T00:00:00.000Z'
updated_at: '2025-01-03T00:00:00.000Z'
'400':
description: Bad Request
content:
application/json:
schema:
type: object
properties:
error:
type: string
hint:
type:
- string
- 'null'
description: 'The next step for the caller: how to authenticate, which scope was missing, or where the route list lives. Always present, and null when this error has no next step to offer.'
example:
error: 'Bad request: HTTP body must be valid JSON'
hint: null
'401':
description: Unauthorized
content:
application/json:
schema:
type: object
properties:
error:
type: string
hint:
type:
- string
- 'null'
description: 'The next step for the caller: how to authenticate, which scope was missing, or where the route list lives. Always present, and null when this error has no next step to offer.'
example:
error: API key missing or invalid
hint: 'Send the token as `Authorization: Bearer <token>`. Create one under Account > Team > Platform Applications (a workspace API key), or obtain one with OAuth 2.1; both use the same scopes. See https://developers.myclickfunnels.com/docs/authentication, or append .md to that URL for markdown.'
'422':
description: Unprocessable Entity — no target selection was supplied; or `stable_id` is not a valid Refine token or not a ContactsFilter; or `stored_filter_id` is unknown, invalid, or belongs to a different workspace.
content:
application/json:
schema:
type: object
properties:
error:
type: string
hint:
type:
- string
- 'null'
description: 'The next step for the caller: how to authenticate, which scope was missing, or where the route list lives. Always present, and null when this error has no next step to offer.'
example:
error: 'provide a selection: stable_id, stored_filter_id, target_ids, or target_all'
hint: null
/contacts/unsubscribe_actions/{id}:
get:
tags:
- Contacts::UnsubscribeAction
summary: Fetch Unsubscribe Action
description: Retrieve a single Contact Unsubscribe Action and its current async progress
operationId: getContactsUnsubscribeActions
parameters:
- $ref: '#/components/parameters/id'
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/ContactsUnsubscribeActionAttributes'
example:
id: 3
public_id: kL9mN0
workspace_id: 42000
filter_id: 7
target_all: false
target_ids: []
target_count: 300
performed_count: 180
created_by_id: 5
approved_by_id: null
scheduled_for: null
started_at: '2025-01-03T00:00:30.000Z'
completed_at: null
created_at: '2025-01-03T00:00:00.000Z'
updated_at: '2025-01-03T00:00:30.000Z'
'401':
description: Unauthorized
content:
application/json:
schema:
type: object
properties:
error:
type: string
hint:
type:
- string
- 'null'
description: 'The next step for the caller: how to authenticate, which scope was missing, or where the route list lives. Always present, and null when this error has no next step to offer.'
example:
error: API key missing or invalid
hint: 'Send the token as `Authorization: Bearer <token>`. Create one under Account > Team > Platform Applications (a workspace API key), or obtain one with OAuth 2.1; both use the same scopes. See https://developers.myclickfunnels.com/docs/authentication, or append .md to that URL for markdown.'
'404':
description: Not Found
content:
application/json:
schema:
type: object
properties:
error:
type: string
hint:
type:
- string
- 'null'
description: 'The next step for the caller: how to authenticate, which scope was missing, or where the route list lives. Always present, and null when this error has no next step to offer.'
example:
error: 'Not found: Record missing'
hint: null
delete:
tags:
- Contacts::UnsubscribeAction
summary: Remove Unsubscribe Action
description: Delete a Contact Unsubscribe Action record
operationId: removeContactsUnsubscribeActions
parameters:
- $ref: '#/components/parameters/id'
responses:
'204':
description: No Content
'401':
description: Unauthorized
content:
application/json:
schema:
type: object
properties:
error:
type: string
hint:
type:
- string
- 'null'
description: 'The next step for the caller: how to authenticate, which scope was missing, or where the route list lives. Always present, and null when this error has no next step to offer.'
example:
error: API key missing or invalid
hint: 'Send the token as `Authorization: Bearer <token>`. Create one under Account > Team > Platform Applications (a workspace API key), or obtain one with OAuth 2.1; both use the same scopes. See https://developers.myclickfunnels.com/docs/authentication, or append .md to that URL for markdown.'
'404':
description: Not Found
content:
application/json:
schema:
type: object
properties:
error:
type: string
hint:
type:
- string
- 'null'
description: 'The next step for the caller: how to authenticate, which scope was missing, or where the route list lives. Always present, and null when this error has no next step to offer.'
example:
error: 'Not found: Record missing'
hint: null
components:
parameters:
id:
name: id
in: path
required: true
schema:
type: string
per_page:
name: per_page
in: query
required: false
description: Records per page. Defaults to 20; raise it up to 100 for bulk reads. A larger value returns 100 records. Zero, a negative or a non-integer value is a 422. The `Link` next-page URL keeps the value, so a client following it keeps the page size. More [in our guides](https://developers.myclickfunnels.com/docs/pagination).
schema:
type: integer
minimum: 1
default: 20
sort_property:
name: sort_property
in: query
description: 'Sort property of a list response. The default is id and thus the created_at order.
If you sort by other properties, we additionally sort by id implicitly as a secondary sort property, so that you can rely on the sort order to be deterministic even if the main sort property ends up with the same values.
'
required: false
schema:
type: string
enum:
- id
- updated_at
sort_order:
name: sort_order
in: query
description: Sort order of a list response. Use 'desc' to reverse the default 'asc' (ascending) sort order. Examples [in our guides](https://developers.myclickfunnels.com/docs/pagination).
required: false
schema:
type: string
enum:
- asc
- desc
after:
name: after
in: query
required: false
schema:
type: string
description: ID of item after which the collection should be returned. More examples and info about pagination [in our guides](https://developers.myclickfunnels.com/docs/pagination).
schemas:
ContactsUnsubscribeActionAttributes:
type: object
title: Contacts Unsubscribe Actions
description: Bulk email-unsubscribe action targeting a collection of contacts
properties:
id:
type: integer
description: Unsubscribe Action ID
public_id:
type:
- string
- 'null'
description: Unsubscribe Action public ID
workspace_id:
type: integer
description: Workspace ID
filter_id:
type:
- integer
- 'null'
description: ID of the `Refine::StoredFilter` that drives target selection. Populated automatically when `stable_id` or `stored_filter_id` is supplied on create. `null` when the action targets explicit `target_ids` or `target_all`.
target_all:
type:
- boolean
- 'null'
description: When `true` the action targets every contact in the workspace. Mutually exclusive with `stable_id`, `stored_filter_id`, and `target_ids`.
target_ids:
type:
- array
- 'null'
items:
type: integer
description: Explicit list of targeted contacts as raw integer IDs. The response echoes the stored integer IDs, not the public IDs passed on create.
target_count:
type:
- integer
- 'null'
description: Total number of contacts selected for this action. `null` until the async job has resolved the audience size.
performed_count:
type:
- integer
- 'null'
description: Number of contacts processed so far. Poll this field alongside `target_count` to track async progress.
created_by_id:
type:
- integer
- 'null'
description: ID of the workspace membership that created this action.
approved_by_id:
type:
- integer
- 'null'
description: ID of the membership that approved this action (reserved for future use).
scheduled_for:
type:
- string
- 'null'
format: date-time
description: When set, the action will not execute until this datetime. `null` means execute immediately.
started_at:
type:
- string
- 'null'
format: date-time
description: Datetime the async job began processing contacts. `null` until started.
completed_at:
type:
- string
- 'null'
format: date-time
description: Datetime the async job finished. `null` until complete.
created_at:
type:
- string
- 'null'
format: date-time
description: Created at datetime
updated_at:
type:
- string
- 'null'
format: date-time
description: Updated at datetime
example:
id: 1
public_id: cD5eF6
workspace_id: 42000
filter_id: 7
target_all: false
target_ids: []
target_count: 300
performed_count: 0
created_by_id: 5
approved_by_id: null
scheduled_for: null
started_at: null
completed_at: null
created_at: '2025-01-01T00:00:00.000Z'
updated_at: '2025-01-01T00:00:00.000Z'
ContactsUnsubscribeActionParameters:
type: object
title: Contacts Unsubscribe Actions
description: Contacts Unsubscribe Actions
properties:
stable_id:
type: string
description: A URL-encoded Refine `stable_id` token — the standard gzip+base64 full-state format used by both the `contacts/filters` API endpoint and the server-rendered filter UI, making tokens interoperable. Returned by `POST /api/v2/workspaces/{workspace_id}/contacts/filters` in the `stable_id` field. Pass the token exactly as returned; do not decode or re-encode it. The server persists the decoded filter so the async job can re-derive the audience at perform time. Mutually exclusive with `stored_filter_id`, `target_ids`, and `target_all`.
stored_filter_id:
type: string
description: The `id` (integer) or `public_id` (string) of a saved `Refine::StoredFilter` scoped to this workspace (must be a ContactsFilter). Also accepted as `filter_id`. Mutually exclusive with `stable_id`, `target_ids`, and `target_all`.
target_ids:
type: array
items:
type: string
description: Explicit list of contacts to unsubscribe, as the `public_id` strings returned by the contacts endpoints. Numeric ids are also accepted. Mutually exclusive with `stable_id`, `stored_filter_id`, and `target_all`.
target_all:
type: boolean
description: Set to `true` to target every contact in the workspace. Use deliberately. Mutually exclusive with `stable_id`, `stored_filter_id`, and `target_ids`.
scheduled_for:
type: string
format: date-time
description: Optional ISO 8601 datetime. When supplied the action is deferred until this time. Omit (or pass `null`) to execute immediately.
example:
contacts_unsubscribe_action:
stored_filter_id: '7'
responses:
InvalidPageSize:
description: Unprocessable Entity - `per_page` must be a positive integer.
content:
application/json:
schema:
type: object
properties:
error:
type: string
hint:
type:
- string
- 'null'
description: Next step for the caller, or null when no additional guidance applies.
example:
error: 'Request unprocessable: per_page must be a positive integer, capped at 100 (got "0")'
hint: null
headers:
PaginationNext:
description: ID of the last item in the current response after which more records exist. You can use it in an `after` query parameter for cursor-based pagination to get to the next page.
schema:
type: string
Link:
description: A direct link to the next page for the cursor-based pagination. It includes the `after` and the Pagination-Next ID value.
schema:
type: string
securitySchemes:
BearerAuth:
type: http
scheme: bearer
description: 'A workspace API key or an OAuth access token, sent as `Authorization: Bearer <token>`.
Both carry the same scope vocabulary as the `OAuth2` scheme below. Category-only
scopes restrict access to the categories they name. Coarse wildcards remain additive:
`read contacts:read` reads every category, while `write contacts:read` can write every
category. Omit coarse scopes when restricting access to specific categories.
Legacy tokens with only coarse scopes retain their existing unrestricted access;
a bare `read` scope alone does not enforce read-only access.
'
OAuth2:
type: oauth2
description: 'OAuth 2.0 authorization code flow for REST integrations. Create a Platform Application
and follow `https://developers.myclickfunnels.com/docs/oauth-20` to connect users.
Authorization server metadata is published at
`https://accounts.myclickfunnels.com/.well-known/oauth-authorization-server`.
Dynamic client registration at `/oauth/register` is for MCP clients only; MCP-scoped
tokens must use `https://agents.myclickfunnels.com/mcp`, not the REST API.
Scopes are least-privilege by category. Ask for the two coarse wildcards (`read`,
`write`) only when an integration genuinely needs the whole workspace; otherwise ask
for the `<category>:read` / `<category>:write` pairs you use. `write` implies `read`
for the same category. Protected resource metadata (RFC 9728) for this API lives at
`https://accounts.myclickfunnels.com/.well-known/oauth-protected-resource`.
'
flows:
authorizationCode:
authorizationUrl: https://accounts.myclickfunnels.com/oauth/authorize
tokenUrl: https://accounts.myclickfunnels.com/oauth/token
refreshUrl: https://accounts.myclickfunnels.com/oauth/token
scopes:
read: Read any resource in the granted workspaces
write: Read and write any resource in the granted workspaces
contacts:read: Read Contacts
contacts:write: Read and write Contacts
workflows:read: Read Workflows (Automations)
workflows:write: Read and write Workflows (Automations)
funnels:read: Read Funnels
funnels:write: Read and write Funnels
sites:read: Read Sites & Design
sites:write: Read and write Sites & Design
courses:read: Read Courses
courses:write: Read and write Courses
emails:read: Read Emails
emails:write: Read and write Emails
blog:read: Read Blog
blog:write: Read and write Blog
community:read: Read Community
community:write: Read and write Community
appointments:read: Read Appointments
appointments:write: Read and write Appointments
opportunities:read: Read Opportunities
opportunities:write: Read and write Opportunities
store:read: Read Store
store:write: Read and write Store
forms:read: Read Forms
forms:write: Read and write Forms
media:read: Read Media
media:write: Read and write Media
webhooks:read: Read Webhooks
webhooks:write: Read and write Webhooks
account:read: Read Account
account:write: Read and write Account
reference:read: Read Reference Data
reference:write: Read and write Reference Data
externalDocs:
description: More in-depth guides and further resources
url: https://developers.myclickfunnels.com
x-provenance:
method: harvested
publisher: ClickFunnels
source: https://accounts.myclickfunnels.com/openapi.json
note: split by refine-openapis from the provider's own published document, verified by fetch (openapi/_original/*.fetch.json);
stamped by stamp-openapi-provenance.py (roadmap#793)