Opt-In Forms API
The Opt-In Forms API provides full CRUD (Create, Read, Update, Delete) operations for managing subscription forms. You can create, list, view, update, and delete opt-in forms programmatically, including their form blocks (text, input fields, and buttons).
Required Permissions
All endpoints require authentication via an API token with appropriate permissions:
- Read Permission: Required for GET endpoints (list, show)
- Write Permission: Required for POST, PATCH, DELETE endpoints
Opt-In Form Object
The opt-in form object contains the following fields:
| Field | Type | Description |
|---|---|---|
| `id` | integer | The unique identifier of the form |
| `identifier` | string (UUID) | A unique UUID for the form, used for embedding |
| `label` | string | The internal name of the form (required) |
| `form_type` | string | Type of form: `web` or `embed` |
| `widget_type` | string | Widget display type (e.g., popup, slide-in, inline) |
| `enabled` | boolean | Whether the form is active (default: true) |
| `allowed_embedding_domains` | array | List of domains where the form can be embedded |
| `theme_settings` | object | Theme customization (colors, typography, layout, effects) |
| `automation_settings` | object | Automation config — see Automation Settings below for the full set of supported keys. |
| `confirmation_email_template_id` | integer | ID of the confirmation email template used when double opt-in is enabled. Must belong to the same channel. |
| `welcome_email_template_id` | integer | ID of the welcome email template sent after a subscriber confirms (if welcome emails are enabled). Must belong to the same channel. |
| `security_settings` | object | Security config (honeypot, rate limiting, Turnstile) |
| `trigger_settings` | object | Display trigger config (timing, scroll, exit intent) |
| `widget_settings` | object | Widget-specific settings |
| `analytics` | object | Analytics data (views_count, unique_views_count, submissions_count, conversion_rate) |
| `is_variant` | boolean | Whether this form is an A/B test variant |
| `variant_name` | string | Name of the variant (if applicable) |
| `variant_weight` | integer | Traffic weight for A/B testing (0-100) |
| `variants_count` | integer | Number of variants for this form |
| `opt_in_form_blocks` | array | Form blocks for the initial view |
| `opt_in_post_submission_blocks` | array | Form blocks for the post-submission view |
| `embed_url` | string | URL to embed the form via JavaScript |
| `created_at` | datetime | When the form was created |
| `updated_at` | datetime | When the form was last updated |
Automation Settings
The automation_settings object accepts the following keys. All are optional; unspecified keys retain their previous value when updating.
| Key | Type | Description |
|---|---|---|
| `tag_list` | string | Comma-separated list of tags applied to subscribers who submit this form. |
| `sequence_ids` | array<integer> | IDs of sequences a confirmed subscriber is enrolled in. |
| `send_welcome_email` | boolean | Whether to send a welcome email after the subscriber confirms (uses `welcome_email_template_id`). |
| `double_opt_in` | boolean | Whether to require email confirmation before activating the subscriber. |
| `include_unsubscribe_link_in_confirmation` | boolean | Whether the confirmation email includes an unsubscribe link in the footer. Defaults to `true`. |
| `confirmation_redirect_url` | string | If set, subscribers are redirected to this URL after confirming instead of seeing Broadcast's confirmation page. Must be `http://` or `https://`. Only applies to opt-in-form-flow confirmations. See Confirmation Pages. |
Form Block Object
Each form block contains the following fields:
| Field | Type | Description |
|---|---|---|
| `id` | integer | The unique identifier of the block |
| `block_type` | string | Type of block (see Block Types below) |
| `form_view` | string | `initial_view` or `post_submission_view` |
| `position` | integer | Order of the block in the form |
| `text_value` | string | Text content (for `text` block type) |
| `heading_level` | string | Heading level (h1-h6) for text blocks |
| `input_field_label` | string | Label for input field |
| `input_field_placeholder` | string | Placeholder text for input field |
| `input_field_value_type` | string | Type of data: `email`, `first_name`, `last_name`, or `name` |
| `custom_field_key` | string | Key for storing custom field data |
| `field_required` | boolean | Whether the field is required |
| `field_validation` | string | Validation rules for the field |
| `button_label` | string | Label for button (default: "Sign Up") |
| `checkbox_label` | string | Label for checkbox |
| `checkbox_field_name` | string | Field name for checkbox value |
| `checkbox_required` | boolean | Whether checkbox must be checked |
| `dropdown_label` | string | Label for dropdown |
| `dropdown_field_name` | string | Field name for dropdown value |
| `dropdown_placeholder` | string | Placeholder text for dropdown |
| `dropdown_options` | array | Array of options for dropdown |
| `radio_label` | string | Label for radio button group |
| `radio_field_name` | string | Field name for radio value |
| `radio_options` | array | Array of options for radio buttons |
| `image_url` | string | URL of the image |
| `image_alt` | string | Alt text for the image |
| `image_alignment` | string | Image alignment (left, center, right) |
| `image_width` | string | Image width |
| `divider_color` | string | Color of the divider |
| `divider_style` | string | Style of divider (solid, dashed, dotted) |
| `divider_width` | string | Width/thickness of the divider |
| `spacer_height` | string | Height of the spacer block |
| `custom_css` | string | Custom CSS styling for the block |
Block Types
text- Display text or headingsinput_field- Collect subscriber data (email, name, custom fields)button- Submit buttoncheckbox- Checkbox for consent or preferencesdropdown- Dropdown select fieldradio- Radio button groupimage- Display an imagedivider- Horizontal divider linespacer- Vertical spacing
List Opt-In Forms
GET /api/v1/opt_in_forms
Retrieve a list of all opt-in forms for the authenticated broadcast channel, ordered alphabetically by label.
Query Parameters
filter(optional): Search forms by labelpage(optional): Page number for paginationlimit(optional): Maximum number of forms to return (default: 250)
Request
curl -X GET \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
http://your-domain.com/api/v1/opt_in_forms
Response
{
"opt_in_forms": [
{
"id": 1,
"identifier": "550e8400-e29b-41d4-a716-446655440000",
"label": "Newsletter Signup",
"form_type": "web",
"enabled": true,
"allowed_embedding_domains": [],
"opt_in_form_blocks": [
{
"id": 1,
"block_type": "text",
"form_view": "initial_view",
"position": 1,
"text_value": "Subscribe to our newsletter",
"input_field_label": null,
"input_field_placeholder": null,
"input_field_value_type": null,
"button_label": null,
"custom_css": null
}
],
"opt_in_post_submission_blocks": [],
"created_at": "2024-01-01T12:00:00Z",
"updated_at": "2024-01-01T12:00:00Z"
}
],
"pagination": {
"total": 1,
"count": 1,
"from": 1,
"to": 1,
"current": 1,
"total_pages": 1
}
}
Get Opt-In Form
GET /api/v1/opt_in_forms/:id
Retrieve details of a specific opt-in form including all its blocks.
Request
curl -X GET \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
http://your-domain.com/api/v1/opt_in_forms/123
Response
{
"id": 123,
"identifier": "550e8400-e29b-41d4-a716-446655440000",
"label": "Newsletter Signup",
"form_type": "web",
"enabled": true,
"allowed_embedding_domains": ["example.com", "blog.example.com"],
"opt_in_form_blocks": [
{
"id": 1,
"block_type": "text",
"form_view": "initial_view",
"position": 1,
"text_value": "Join our newsletter!",
"input_field_label": null,
"input_field_placeholder": null,
"input_field_value_type": null,
"button_label": null,
"custom_css": null
},
{
"id": 2,
"block_type": "input_field",
"form_view": "initial_view",
"position": 2,
"text_value": null,
"input_field_label": "Email Address",
"input_field_placeholder": "[email protected]",
"input_field_value_type": "email",
"button_label": null,
"custom_css": null
},
{
"id": 3,
"block_type": "button",
"form_view": "initial_view",
"position": 3,
"text_value": null,
"input_field_label": null,
"input_field_placeholder": null,
"input_field_value_type": null,
"button_label": "Subscribe Now",
"custom_css": null
}
],
"opt_in_post_submission_blocks": [
{
"id": 4,
"block_type": "text",
"form_view": "post_submission_view",
"position": 1,
"text_value": "Thanks for subscribing!",
"input_field_label": null,
"input_field_placeholder": null,
"input_field_value_type": null,
"button_label": null,
"custom_css": null
}
],
"created_at": "2024-01-01T12:00:00Z",
"updated_at": "2024-01-01T12:00:00Z"
}
Create Opt-In Form
POST /api/v1/opt_in_forms
Create a new opt-in form with blocks.
Parameters
label(required): Internal name of the formform_type(optional):web(default) orembedenabled(optional): Whether the form is active (default: true)allowed_embedding_domains(optional): Array of domains where the form can be embeddedopt_in_form_blocks_attributes(optional): Array of form blocks for the initial view
Request
curl -X POST \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"opt_in_form": {
"label": "Newsletter Signup",
"form_type": "web",
"enabled": true,
"allowed_embedding_domains": ["example.com"],
"opt_in_form_blocks_attributes": [
{
"block_type": "text",
"text_value": "Subscribe to our newsletter!",
"position": 1
},
{
"block_type": "input_field",
"input_field_label": "Email",
"input_field_value_type": "email",
"input_field_placeholder": "[email protected]",
"position": 2
},
{
"block_type": "button",
"button_label": "Sign Up",
"position": 3
}
]
}
}' \
http://your-domain.com/api/v1/opt_in_forms
Response
{
"id": 123,
"identifier": "550e8400-e29b-41d4-a716-446655440000",
"label": "Newsletter Signup",
"form_type": "web",
"enabled": true,
"allowed_embedding_domains": ["example.com"],
"opt_in_form_blocks": [
{
"id": 1,
"block_type": "text",
"form_view": "initial_view",
"position": 1,
"text_value": "Subscribe to our newsletter!",
"input_field_label": null,
"input_field_placeholder": null,
"input_field_value_type": null,
"button_label": null,
"custom_css": null
},
{
"id": 2,
"block_type": "input_field",
"form_view": "initial_view",
"position": 2,
"text_value": null,
"input_field_label": "Email",
"input_field_placeholder": "[email protected]",
"input_field_value_type": "email",
"button_label": null,
"custom_css": null
},
{
"id": 3,
"block_type": "button",
"form_view": "initial_view",
"position": 3,
"text_value": null,
"input_field_label": null,
"input_field_placeholder": null,
"input_field_value_type": null,
"button_label": "Sign Up",
"custom_css": null
}
],
"opt_in_post_submission_blocks": [],
"created_at": "2024-01-01T12:00:00Z",
"updated_at": "2024-01-01T12:00:00Z"
}
Update Opt-In Form
PATCH /api/v1/opt_in_forms/:id
Update an existing opt-in form.
Parameters
All parameters are optional. Only include the fields you want to update:
label: Internal name of the formform_type:weborembedenabled: Whether the form is activeallowed_embedding_domains: Array of domainsopt_in_form_blocks_attributes: Array of form blocks (includeidto update,_destroy: trueto delete)
Request
curl -X PATCH \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"opt_in_form": {
"label": "Updated Form Name",
"enabled": false,
"opt_in_form_blocks_attributes": [
{
"id": 1,
"text_value": "Updated headline text"
},
{
"id": 2,
"_destroy": true
}
]
}
}' \
http://your-domain.com/api/v1/opt_in_forms/123
Response
Returns the updated opt-in form object.
Delete Opt-In Form
DELETE /api/v1/opt_in_forms/:id
Delete an opt-in form and all its blocks.
Request
curl -X DELETE \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
http://your-domain.com/api/v1/opt_in_forms/123
Response
{
"message": "Opt-in form deleted successfully"
}
Get Form Analytics
GET /api/v1/opt_in_forms/:id/analytics
Retrieve analytics data for a specific opt-in form.
Query Parameters
start_date(optional): Start date for analytics period (default: 30 days ago)end_date(optional): End date for analytics period (default: today)
Request
curl -X GET \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
"http://your-domain.com/api/v1/opt_in_forms/123/analytics?start_date=2024-01-01&end_date=2024-01-31"
Response
{
"form_id": 123,
"identifier": "550e8400-e29b-41d4-a716-446655440000",
"period": {
"start_date": "2024-01-01",
"end_date": "2024-01-31"
},
"totals": {
"views": 1500,
"unique_views": 1200,
"submissions": 150,
"conversion_rate": 12.5
},
"daily": [
{
"date": "2024-01-01",
"views": 50,
"unique_views": 45,
"submissions": 5
}
],
"variants": [
{
"id": 124,
"name": "Variant A",
"weight": 50,
"views": 750,
"submissions": 80,
"conversion_rate": 10.67
}
]
}
Create A/B Test Variant
POST /api/v1/opt_in_forms/:id/variants
Create a new A/B test variant from an existing form.
Parameters
name(optional): Name for the variant (default: "Variant N")weight(optional): Traffic weight for the variant (default: 50)
Request
curl -X POST \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Variant B - New Headline",
"weight": 50
}' \
http://your-domain.com/api/v1/opt_in_forms/123/variants
Response
Returns the created variant form object with status 201.
Duplicate Form
POST /api/v1/opt_in_forms/:id/duplicate
Create a copy of an existing form.
Parameters
label(optional): Label for the new form (default: "Original Label (Copy)")
Request
curl -X POST \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"label": "Newsletter Signup v2"
}' \
http://your-domain.com/api/v1/opt_in_forms/123/duplicate
Response
Returns the duplicated form object with status 201.
Error Responses
If the request is invalid, the response will include an appropriate HTTP status code and error message:
401 Unauthorized
{
"error": "Unauthorized"
}
This error occurs when: - No authorization header is provided - The token is invalid or expired - The token doesn't have the required permissions
404 Not Found
{
"error": "Opt-in form not found"
}
This error occurs when: - The form ID doesn't exist - The form belongs to a different broadcast channel
422 Unprocessable Entity
{
"error": "Label can't be blank"
}
This error occurs when: - Required fields are missing - Validation fails for any reason
Usage Example: Creating a Complete Form
Here's an example of creating a complete opt-in form with all block types:
curl -X POST \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"opt_in_form": {
"label": "Lead Capture Form",
"form_type": "embed",
"enabled": true,
"allowed_embedding_domains": ["example.com", "blog.example.com"],
"opt_in_form_blocks_attributes": [
{
"block_type": "text",
"text_value": "Get our weekly newsletter!",
"position": 1
},
{
"block_type": "input_field",
"input_field_label": "First Name",
"input_field_value_type": "first_name",
"input_field_placeholder": "John",
"position": 2
},
{
"block_type": "input_field",
"input_field_label": "Email Address",
"input_field_value_type": "email",
"input_field_placeholder": "[email protected]",
"position": 3
},
{
"block_type": "button",
"button_label": "Subscribe",
"position": 4
}
]
}
}' \
http://your-domain.com/api/v1/opt_in_forms