Intro
Endpoint: https://api.omnisend.com/api/forms
Create, configure, enable, and render Omnisend signup forms. A form defines its content (a hierarchical layout of steps, sections, rows, columns, and blocks) and the targeting rules that decide when and to whom it is shown.
New forms are created in draft status and are not shown to visitors until enabled with POST /api/forms/{formID}/enable.
Display types
Each form has a displayType that controls how it is presented to visitors. Choose it based on how prominent and interruptive the signup experience should be.
displayType | Description |
|---|---|
popup | Modal centered over the page that dims the background. Highest visibility; best for launch offers, discounts, and exit-intent capture where interrupting the visitor is acceptable. |
flyout | Compact panel anchored to a page corner that leaves the page usable. Less intrusive; suited to always-on signup while the visitor keeps browsing. |
embedded | Rendered inline within the host page's content. Use for a permanent signup block placed in a section, sidebar, or footer rather than an overlay. |
landingPage | Full standalone page hosted by Omnisend. Use for campaigns driven by ads, emails, or shared links where there is no host site to embed into. |
fullscreen | Overlay that covers the entire viewport. Maximum attention; best for high-value offers where taking over the screen is justified. |
Only popup, flyout and fullscreen forms are eligible for A/B testing (see the Form A/B Setups reference).
Form content structure
A form's content follows a strict hierarchy:
Content
└── Steps[] (1–2 screens of the form)
└── Sections[]
└── Rows[]
└── Columns[] (up to 4 per row)
└── Blocks[]
- Steps are the screens a visitor moves through (a single-step form has one; multi-step forms have two).
contentalso accepts optionalsuccessStep,subscribedStep, andunavailablePageStepscreens shown after submission or when the form is unavailable. - Sections are top-level content containers within a step, each with its own style properties.
- Rows group columns horizontally within a section.
- Columns define layout width (pixels or percent) and contain blocks. A row holds up to four columns.
- Blocks are the actual content elements (text, image, button, input fields, etc.).
Sections, rows, columns, and blocks each carry a server-generated id that is assigned on create and returned in responses. You may omit these IDs from create/update requests.
content also carries generalSettings — the shared presentation of the form (container width and overlay color, body styling, link color, button/text presets, field styles, and position) — and an optional teaser shown before or after the form.
Block types
Each block's type field selects its content element and the matching configuration object (for example a text block carries text, an image block carries image).
| Type | Description |
|---|---|
text | Rich text content with HTML formatting |
image | Image referencing an existing image in the Images API, with optional link and alt text |
button | Clickable button (link, submit, close, or nextStep behavior) |
lineSpace | Divider line or blank spacer for layout separation |
emailField | Email input field |
phoneNumberField | Phone number input field with default country code |
inputField | Generic profile input field (maps to a contact property) |
legal | Legal consent block (gdpr or tcpa) |
dateField | Date input field |
dropdownField | Dropdown selection field |
radioField | Radio selection field |
checkboxField | Checkbox selection field |
wheelOfFortune | Gamified wheel with configurable slices and win probabilities |
discount | Discount code block (wheelOfFortune or static source) |
countdownTimer | Countdown timer ending at a fixed timestamp |
Each block carries its own configuration object (selected by type), optional styleProperties, and an optional stylePresetID referencing a shared preset (see Style presets below).
Block configuration
The block object holds one configuration object matching its type. The field-level configuration for each type is below.
text — the text field is an HTML string, e.g. "<p>Subscribe to our newsletter</p>".
image (image object)
| Field | Description |
|---|---|
id | ID of an existing image in the Images API |
link | URL opened when the image is clicked |
altText | Alternative text (max 200) |
width / height | Original image dimensions in pixels |
resizeWidth | Rendered width in pixels (max 2000) |
button (button object)
| Field | Description |
|---|---|
type | Behavior on click: link, submit, close, nextStep (link requires link) |
text | Button label (max 200) |
link | URL opened when type is link |
isFullWidth | Whether the button spans the full width |
lineSpace (lineSpace object)
| Field | Description |
|---|---|
type | line (divider) or space (blank spacer) |
width | Divider width percentage 1–100 (line only) |
height | Line thickness 1–60px, or space height 12–240px |
Input fields — emailField, phoneNumberField, inputField, dateField, dropdownField, radioField, checkboxField. They share these common fields:
| Field | Description |
|---|---|
label | Field label (max 300) |
placeholder | Placeholder text (max 250; not on date/radio/checkbox) |
isRequired | Whether the field must be filled |
requiredMessage | Message shown when a required field is empty |
errorMessage | Message shown for invalid input (email, phone, date) |
Type-specific fields:
| Type | Additional fields |
|---|---|
emailField | (common fields only) |
phoneNumberField | defaultCountryCode (ISO 3166-1 alpha-2, e.g. US) |
inputField | profileField (firstName, lastName, address, city, state, zipCode, custom), customProfileField when custom |
dateField | profileField (birthdate, custom), customProfileField, format (YYYY/MM/DD, MM/DD/YYYY, DD/MM/YYYY) |
dropdownField | profileField (country, gender, custom), customProfileField, options[] (value/label, up to 100) |
radioField | profileField (gender, custom), customProfileField, options[] |
checkboxField | profileField (custom), customProfileField, options[] |
legal (legal object)
| Field | Description |
|---|---|
type | Consent type: gdpr or tcpa |
label | Consent label shown next to the checkbox |
description | Consent description text |
link | URL to the privacy policy |
requiredMessage | Message shown when consent is required but not given |
discount (discount object)
| Field | Description |
|---|---|
type | Source: static (fixed code) or wheelOfFortune (awarded by the wheel) |
code | Static discount code (required when type is static) |
countdownTimer (countdownTimer object)
| Field | Description |
|---|---|
endsAt | Countdown end timestamp (RFC 3339, e.g. 2026-02-20T14:00:00Z) |
wheelOfFortune (wheelOfFortune object)
| Field | Description |
|---|---|
slices | 3–20 wheel slices (see below) |
pointerColor | Wheel pointer color (hex) |
width | Wheel width percentage 30–100 |
Each slice:
| Field | Description |
|---|---|
text | Slice label (max 250) |
discountCode | Discount code awarded for the slice |
probability | Win probability percentage 0–100 |
isLosing | Whether the slice is a losing slice |
backgroundColor / textColor | Slice colors (hex or transparent) |
imageUrl / altText | Optional slice image and its alt text |
General settings
content.generalSettings controls the presentation shared across the whole form.
| Field | Description |
|---|---|
content | Form container width (300px–1000px) and overlay color shown behind the form |
body | Form body background color, border radius, width, style, and color |
link | Link color used in text blocks |
buttonPresets | Reusable button styles referenced by blocks via stylePresetID (required — see Style presets below) |
textPresets | Reusable text styles referenced by blocks via stylePresetID (required — see Style presets below) |
fieldStyles | Styling shared across input fields: label, placeholder, and field appearance |
closeButton | Close button color, background, and visibility |
backgroundImage | Optional background image (references an image in the Images API) with position, fit, padding, and size |
position | Where the form appears on the page (e.g. middleCenter, bottomLeft) |
Style presets
Forms use button presets and text presets so blocks share consistent styling. A block applies a preset by setting its stylePresetID to the preset id.
generalSettings.buttonPresets must include these three presets:
primary_button | secondary_button | tertiary_button |
|---|
generalSettings.textPresets must include these five presets:
heading_large | heading_medium | heading_small | paragraph | footnote |
|---|
Additional form settings
Beyond content and targeting, a form accepts these optional top-level settings:
| Field | Description |
|---|---|
doubleOptIn | Double opt-in flow: confirmation email content plus a confirmation page or redirect |
socialMediaSharing | Social preview metadata (title, description, image) for shared landing pages |
autoRedirect | Redirect applied after submission |
contactTags | Tags applied to contacts who submit the form (up to 100) |
clickOutside | Whether clicking outside the form closes it |
recaptcha | reCAPTCHA spam protection toggle |
Each content also supports optional post-submission screens — successSections, subscribedSections, and unavailablePageSections — and a teaser shown before or after the form.
Targeting
targeting controls when and to whom a form is shown. All targeting rules are optional; omit the object entirely to show the form everywhere its display type allows.
| Rule | Description |
|---|---|
url | Show or hide the form on matching page URLs (exact or contains matches) |
display | Display triggers: viewed page count, seconds on page, scroll depth, exit intent |
frequency | How often the form reappears (second, minute, hour, or day units) |
device | Limit to mobile or desktop |
scheduling | Active window (startsAt/endsAt, RFC 3339) |
isBackInStock | Limit to back-in-stock visitors |
audience | Target subscribers or notSubscribers |
segments | Include/exclude by segment membership (segment IDs) |
location | Include/exclude by country, with optional state filtering |
utm | Match UTM parameters (id, source, medium, campaign, term, content) |
source | Match traffic source (googleAds, organic, direct, facebook, instagram, omnisendCommunication) |
Constraints and pagination
| Constraint | Value |
|---|---|
| Form name | 1–256 characters |
| Container width | 300px–1000px |
| Steps per form | 1–2 |
| Columns per row | Up to 4 |
| Font size | 8px–96px (4px minimum for legal blocks) |
| IDs (path parameters) | 24-character hexadecimal |
List page size (limit) | 1–250 (default 100) |
| Forms sort fields | createdAt (default), updatedAt, name |
| Sort direction | asc, desc (default) |
List endpoints use cursor-based pagination: pass the after cursor from a response to fetch the next page, or before for the previous page (after and before cannot be combined). Sort parameters are only needed on the first request — subsequent cursor requests reuse the sort settings embedded in the cursor. See Pagination for details.
Scopes
| Scope | Grants |
|---|---|
forms.read | List and get forms, templates, and A/B setups |
forms.write | Create, update, delete, enable, disable, and render forms; render templates; manage A/B setups |
Example: Create a form
POST /api/forms creates a new form with the provided content, styling, and targeting. The form starts in draft status.
curl --request POST \
--url https://api.omnisend.com/api/forms \
--header 'Authorization: Omnisend-API-Key YOUR_API_KEY' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'Omnisend-Version: 2026-preview' \
--data '{
"name": "Newsletter Signup",
"displayType": "popup",
"content": {
"generalSettings": {
"content": { "width": "600px", "color": "#000000" },
"body": {
"backgroundColor": "#ffffff",
"borderRadius": "8px",
"borderWidth": "1px",
"borderStyle": "solid",
"borderColor": "#cccccc"
},
"link": { "color": "#0000ee" },
"buttonPresets": [
{
"id": "primary_button",
"name": "Primary",
"styles": {
"backgroundColor": "#000000",
"borderRadius": "8px",
"borderWidth": "1px",
"borderStyle": "solid",
"borderColor": "#000000",
"fontWeight": "bold",
"fontStyle": "normal",
"textDecoration": "none",
"fontFamily": "Arial",
"fontSize": "16px",
"color": "#ffffff"
}
},
{
"id": "secondary_button",
"name": "Secondary",
"styles": {
"backgroundColor": "#ffffff",
"borderRadius": "8px",
"borderWidth": "1px",
"borderStyle": "solid",
"borderColor": "#000000",
"fontWeight": "normal",
"fontStyle": "normal",
"textDecoration": "none",
"fontFamily": "Arial",
"fontSize": "16px",
"color": "#000000"
}
},
{
"id": "tertiary_button",
"name": "Tertiary",
"styles": {
"backgroundColor": "transparent",
"borderRadius": "0px",
"borderWidth": "0px",
"borderStyle": "solid",
"borderColor": "transparent",
"fontWeight": "normal",
"fontStyle": "normal",
"textDecoration": "underline",
"fontFamily": "Arial",
"fontSize": "16px",
"color": "#000000"
}
}
],
"textPresets": [
{ "id": "heading_large", "name": "Heading Large", "styles": { "fontFamily": "Arial", "fontSize": "32px", "color": "#000000", "lineHeight": "125%" } },
{ "id": "heading_medium", "name": "Heading Medium", "styles": { "fontFamily": "Arial", "fontSize": "24px", "color": "#000000", "lineHeight": "125%" } },
{ "id": "heading_small", "name": "Heading Small", "styles": { "fontFamily": "Arial", "fontSize": "20px", "color": "#000000", "lineHeight": "125%" } },
{ "id": "paragraph", "name": "Paragraph", "styles": { "fontFamily": "Arial", "fontSize": "16px", "color": "#000000", "lineHeight": "150%" } },
{ "id": "footnote", "name": "Footnote", "styles": { "fontFamily": "Arial", "fontSize": "12px", "color": "#757575", "lineHeight": "150%" } }
],
"fieldStyles": {
"fontFamily": "Arial",
"fontSize": "14px",
"errorColor": "#ff0000",
"label": { "color": "#000000" },
"placeholder": { "color": "#999999" },
"field": {
"color": "#000000",
"backgroundColor": "#ffffff",
"borderRadius": "4px",
"borderStyle": "solid",
"borderColor": "#cccccc",
"borderWidth": "1px"
}
}
},
"steps": [
{
"sections": [
{
"rows": [
{
"columns": [
{
"width": "100%",
"blocks": [
{ "type": "text", "role": "title", "text": "<p>Subscribe to our newsletter</p>", "stylePresetID": "heading_large" },
{
"type": "emailField",
"emailField": {
"placeholder": "[email protected]",
"isRequired": true,
"requiredMessage": "Email is required",
"errorMessage": "Enter a valid email address",
"label": "Email"
}
},
{ "type": "button", "button": { "type": "submit", "text": "Subscribe", "link": "", "isFullWidth": true } }
]
}
]
}
]
}
]
}
]
},
"targeting": { "display": { "afterSeconds": 5 }, "device": "desktop" }
}'Example: Enable a form
POST /api/forms/{formID}/enable publishes the form and starts serving it to visitors according to its targeting rules. The call is idempotent.
curl --request POST \
--url https://api.omnisend.com/api/forms/000000000000000000000001/enable \
--header 'Authorization: Omnisend-API-Key YOUR_API_KEY' \
--header 'Omnisend-Version: 2026-preview' \
--header 'accept: application/json'