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 (tag_list, sequence_ids, welcome email, double opt-in) |
| `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 |
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