---
title: "Create Enroll Action"
method: POST
path: "/workspaces/{workspace_id}/contacts/enroll_actions"
tags: ["Contacts::EnrollAction"]
---

# Create Enroll Action

`POST /workspaces/{workspace_id}/contacts/enroll_actions`

Bulk-enroll a collection of contacts into course sections. Pass `course_ids` to enroll in every section of those courses, or `section_ids` for specific sections (or both). The action runs asynchronously — poll the returned record with `GET /api/v2/contacts/enroll_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.

## Path parameters

- `workspace_id` integer, required

## Request body

- object
  - `contacts_enroll_action` ContactsEnrollActionParameters — Contacts Enroll Actions
    - `course_ids` string[] — Public IDs of the courses to enroll contacts into. Contacts are enrolled into every section of each course. Provide `course_ids`, `section_ids`, or both.
    - `section_ids` string[] — Public IDs of specific course sections to enroll contacts into. Use when you want finer-grained control than `course_ids`.
    - `stable_id` string — 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` string — 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` string[] — Explicit list of contacts to enroll, 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` boolean — 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` string, date-time — Optional ISO 8601 datetime. When supplied the action is deferred until this time. Omit (or pass `null`) to execute immediately.

## Response `201`

Created

- ContactsEnrollActionAttributes — Bulk course-enrollment action targeting a collection of contacts
  - `id` integer — Enroll Action ID
  - `public_id` string, nullable — Enroll Action public ID
  - `workspace_id` integer — Workspace ID
  - `course_ids` integer[], nullable — The raw integer IDs of the courses contacts were enrolled into. The response echoes stored integer IDs, not the public IDs passed on create.
  - `section_ids` integer[], nullable — The raw integer IDs of the course sections contacts were enrolled into. The response echoes stored integer IDs, not the public IDs passed on create.
  - `filter_id` integer, nullable — 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` boolean, nullable — When `true` the action targets every contact in the workspace. Mutually exclusive with `stable_id`, `stored_filter_id`, and `target_ids`.
  - `target_ids` integer[], nullable — 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` integer, nullable — Total number of contacts selected for this action. `null` until the async job has resolved the audience size.
  - `performed_count` integer, nullable — Number of contacts processed so far. Poll this field alongside `target_count` to track async progress.
  - `created_by_id` integer, nullable — ID of the workspace membership that created this action.
  - `scheduled_for` string, date-time, nullable — When set, the action will not execute until this datetime. `null` means execute immediately.
  - `started_at` string, date-time, nullable — Datetime the async job began processing contacts. `null` until started.
  - `completed_at` string, date-time, nullable — Datetime the async job finished. `null` until complete.
  - `created_at` string, date-time, nullable — Created at datetime
  - `updated_at` string, date-time, nullable — Updated at datetime

## Other responses

- `400` — Bad Request
- `401` — Unauthorized
- `422` — 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.

---

[API](https://skmtc.dev/myclickfunnels/apis/clickfunnels-api.md) · [All operations](https://skmtc.dev/myclickfunnels/apis/clickfunnels-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/myclickfunnels/clickfunnels-api/revisions/ae6313eaa176/schema)
