openapi: 3.0.0
info:
contact: {}
description: API for managing email content, templates and universal layouts
title: Email Content API
version: '5.0'
x-api-evangelist:
harvested: '2026-08-13'
method: searched
source: https://dash.readme.com/api/v1/api-registry/9c1ckrq8msfxryye
source-note: Published by Omnisend on its own docs host api-docs.omnisend.com (ReadMe project @omnisend,
branch v2026-03-15); registry document referenced by the reference page as oasPublicUrl.
paths:
/email-content/{id}:
get:
description: 'With this endpoint you can get email content by ID.
**Scopes:**
`email-templates.read`
**Rate Limiting:**
This endpoint is rate limited to 400 requests per minute.'
parameters:
- description: Content ID (24 character hexadecimal)
in: path
name: id
required: true
schema:
type: string
- $ref: '#/components/parameters/APIVersionHeader'
responses:
'200':
description: Content
content:
application/json:
schema:
$ref: '#/components/schemas/Content'
'400':
description: Invalid content ID or missing brand ID
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'401':
description: Authentication is missing or invalid
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'403':
description: Insufficient permissions for this operation
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'404':
description: Content not found
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'410':
description: API version has been retired
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'429':
description: Rate limit exceeded
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'500':
description: Unexpected error occurred
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
security:
- Bearer:
- email-templates.read
- ApiKeyAuth: []
summary: Get email content
tags:
- Email Content
put:
description: 'With this endpoint you can update (fully replace) email content by ID.
The full content structure must be provided in the request body.
**Scopes:**
`email-templates.write`
**Rate Limiting:**
This endpoint is rate limited to 400 requests per minute.'
parameters:
- description: Content ID (24 character hexadecimal)
in: path
name: id
required: true
schema:
type: string
- $ref: '#/components/parameters/APIVersionHeader'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Content'
description: Email content to update
required: true
responses:
'200':
description: Updated Content
content:
application/json:
schema:
$ref: '#/components/schemas/Content'
'400':
description: Invalid content ID, missing brand ID, invalid content structure, or validation
errors
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'401':
description: Authentication is missing or invalid
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'403':
description: Insufficient permissions for this operation
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'404':
description: Content not found
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'409':
description: Content is locked and cannot be modified
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'410':
description: API version has been retired
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'413':
description: Request body too large - exceeds 1 MB limit
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'429':
description: Rate limit exceeded
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'500':
description: Unexpected error occurred
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
security:
- Bearer:
- email-templates.write
- ApiKeyAuth: []
summary: Update email content
tags:
- Email Content
/email-content/{id}/render:
post:
description: 'With this endpoint you can render email content to HTML by ID.
The content is rendered with an empty data context (no contact, no marketing activity).
**Scopes:**
`email-templates.write`
**Rate Limiting:**
This endpoint is rate limited to 40 requests per minute.'
parameters:
- $ref: '#/components/parameters/APIVersionHeader'
- description: Content ID (24 character hexadecimal)
in: path
name: id
required: true
schema:
type: string
responses:
'200':
description: Rendered HTML body
content:
application/json:
schema:
additionalProperties:
type: string
type: object
'400':
description: Invalid content ID or missing brand ID
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'401':
description: Authentication is missing or invalid
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'403':
description: Insufficient permissions for this operation
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'404':
description: Content not found
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'410':
description: API version has been retired
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'422':
description: Liquid syntax error in template
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'429':
description: Rate limit exceeded
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
'500':
description: Unexpected error occurred
content:
application/json:
schema:
$ref: '#/components/schemas/APIErrorResponse'
security:
- Bearer:
- email-templates.write
- ApiKeyAuth: []
summary: Render email content
tags:
- Email Content
servers:
- url: https://api.omnisend.com/api
components:
parameters:
APIVersionHeader:
description: API version that specifies the response format and behaviour
in: header
name: Omnisend-Version
required: true
schema:
type: string
default: '2026-03-15'
securitySchemes:
ApiKeyAuth:
in: header
name: Authorization
type: apiKey
Bearer:
type: oauth2
flows:
clientCredentials:
tokenUrl: https://app.omnisend.com/oauth2/token
scopes:
email-templates.read: Allows reading email templates and universal layouts
email-templates.write: Allows create, update, delete email templates and universal layouts
schemas:
APIErrorResponse:
description: RFC 9457 Problem Details error response
properties:
detail:
description: Human-readable explanation specific to this occurrence
example: One or more fields are invalid.
type: string
errors:
description: List of field-level validation errors
items:
$ref: '#/components/schemas/FieldError'
type: array
instance:
description: URI reference identifying the specific occurrence
example: urn:omnisend:request:abc123
type: string
status:
description: HTTP status code
example: 400
type: integer
title:
description: Short human-readable summary of the problem
example: Validation failed
type: string
type:
description: URI reference identifying the problem type
example: https://problems.omnisend.com/validation-failed
type: string
type: object
Annotation:
description: Gmail annotation settings
properties:
discountDescription:
description: Gmail discount description - description of the discount or promotion to display
in Gmail promotion tab together with the discount code.
example: 15% off
type: string
isEnabled:
description: Gmail annotation enabled
example: true
type: boolean
type: object
Block:
description: Block is a single element in the email template
properties:
button:
$ref: '#/components/schemas/Button'
components:
description: 'Components - the parts a block renders that are not covered by its own content
field.
Some blocks tag each part with a ''role'', and which roles they need is decided by their ''type'':
a ''discount'' block holds the code, the redeem button and the expiry date, a ''menu'' block
holds
its items, a ''product'' block holds the product''s image, title, description, prices and
button.
Other blocks nest components without a role, and blocks that render everything from a dedicated
content field have no components at all. See BlockComponent.'
items:
$ref: '#/components/schemas/BlockComponent'
type: array
discount:
$ref: '#/components/schemas/Discount'
dynamicDiscount:
$ref: '#/components/schemas/Discount'
html:
description: 'Deprecated: use HTMLCode instead. Read-only, will be removed in future versions.'
example: <p>Hello</p>
readOnly: true
type: string
htmlCode:
$ref: '#/components/schemas/HTMLCode'
id:
description: Block unique identifier - must be unique within the template
example: 6699a0000000000000000000
maxLength: 24
minLength: 24
type: string
image:
$ref: '#/components/schemas/Image'
lineSpace:
$ref: '#/components/schemas/LineSpace'
logo:
$ref: '#/components/schemas/Logo'
orderAddresses:
$ref: '#/components/schemas/OrderAddresses'
orderProducts:
$ref: '#/components/schemas/OrderProducts'
orderSummary:
$ref: '#/components/schemas/OrderSummary'
orderTotal:
$ref: '#/components/schemas/OrderTotal'
preheader:
$ref: '#/components/schemas/Preheader'
product:
$ref: '#/components/schemas/Product'
role:
description: Block role
enum:
- product_image
- product_title
- product_description
- product_prices
- product_price
- product_button
- discount_code
- discount_button
- discount_expiration_date
- product_current_price
- product_old_price
- menu_text
example: product_title
type: string
secondaryStylePresetID:
description: Secondary style preset ID - ID of the secondary style preset. Used for order blocks
styling as smaller text style.
example: paragraph
type: string
social:
$ref: '#/components/schemas/Social'
staticDiscount:
$ref: '#/components/schemas/Discount'
stylePresetID:
description: 'Style preset ID - ID of the style preset. Used for Button or Text block styling.
ID must be present in template General Settings.'
example: paragraph
type: string
styleProperties:
allOf:
- $ref: '#/components/schemas/StyleProperties'
description: Style properties - style properties of the block
text:
description: Text content of the block - supports HTML formatting and personalization tags
example: <p>Hello [[contact.first_name]]</p>
type: string
type:
description: "Block type.\nNotes:\n - 'html' is read-only and cannot be set on create/update.\n\
\ - 'menu' is a container block with no dedicated content field — items must be provided\
\ via 'components' as text blocks with role 'menu_text', and styling is configured through\
\ 'stylePresetID' and 'styleProperties'.\n - 'discount' is the block for an offer. The offer\
\ is configured in the 'discount' object, and everything the recipient sees must be provided\
\ via 'components' as role-tagged blocks — a text block with role 'discount_code' (required,\
\ exactly one), plus an optional button with role 'discount_button' and an optional text block\
\ with role 'discount_expiration_date'. The store issues a code per recipient when the email\
\ is sent, so 'discount.code' carries the placeholder XXXX-XXXX-XXXX. Writing the offer as\
\ plain text instead leaves a code that was never created in the store, so the recipient cannot\
\ redeem it.\n - 'dynamicDiscount' is the WooCommerce equivalent of 'discount' — same object,\
\ same components and placeholder, except that the 'discount_button' component is required.\
\ A 'discount' block on a WooCommerce store is skipped when the email is sent, so it ships\
\ the placeholder to the recipient as the code.\n - 'staticDiscount' (WooCommerce) instead\
\ carries one fixed code that already exists in the store, and gets no code at send time.\
\ It does not accept a 'discount_button'. Use it only when the brand explicitly asked for\
\ a fixed code."
enum:
- html
- htmlCode
- text
- image
- video
- logo
- menu
- social
- button
- product
- discount
- staticDiscount
- dynamicDiscount
- orderSummary
- orderProducts
- orderTotal
- orderAddresses
- lineSpace
- preheader
- price
example: text
type: string
video:
$ref: '#/components/schemas/Video'
type: object
BlockComponent:
description: 'BlockComponent is a block nested inside a parent block, carrying one part of what
that parent renders. Some parent blocks assign a ''role'' to each of their parts, and then the
parent''s ''type'' decides which roles it needs: a ''discount'' block requires text/discount_code
and accepts button/discount_button and text/discount_expiration_date; its WooCommerce equivalents
take the same roles, except that ''dynamicDiscount'' requires the button and ''staticDiscount''
does not accept one. A ''menu'' block holds its items as text/menu_text. The product_* roles belong
to a ''product'' block, whose price/product_prices component nests text/product_current_price
and text/product_old_price components of its own. Blocks that do not assign roles nest their components
without one.'
properties:
button:
allOf:
- $ref: '#/components/schemas/Button'
description: Button content of the component - used by roles 'discount_button' and 'product_button'.
components:
description: Components nested inside this component. Only role 'product_prices' uses them.
items:
$ref: '#/components/schemas/BlockComponent'
type: array
html:
description: 'Deprecated: use Text instead. Read-only, will be removed in future versions.'
example: <p>Hello</p>
readOnly: true
type: string
id:
description: Component unique identifier - must be unique within the template
example: 6699a0000000000000000000
maxLength: 24
minLength: 24
type: string
image:
allOf:
- $ref: '#/components/schemas/Image'
description: Image content of the component - used by role 'product_image'.
role:
description: 'Role the component plays inside its parent block - set only where the parent block
assigns
roles to its parts, and omitted otherwise.'
enum:
- discount_code
- discount_button
- discount_expiration_date
- menu_text
- product_image
- product_title
- product_description
- product_prices
- product_price
- product_button
- product_current_price
- product_old_price
example: discount_code
type: string
stylePresetID:
description: Style preset ID - ID of the style preset. ID must be present in template General
Settings.
example: paragraph
type: string
styleProperties:
allOf:
- $ref: '#/components/schemas/StyleProperties'
description: Style properties - style properties of the component
text:
description: 'Text content of the component - supports HTML formatting and personalization tags.
For role ''discount_code'' this is the code the recipient sees; on a platform that issues
its own codes
it is replaced at send time, so it carries the placeholder XXXX-XXXX-XXXX.'
example: <p>XXXX-XXXX-XXXX</p>
type: string
type:
description: Component type. Only these block types can be nested as a component.
enum:
- text
- button
- image
- price
example: text
type: string
type: object
Body:
description: Body settings for the template
properties:
backgroundColor:
description: Body background color
example: '#EDEEF0'
type: string
backgroundImageID:
description: Body background image ID - must be present in Image API
example: 68f0ad8a72105230579523cd
maxLength: 24
minLength: 24
type: string
backgroundRepeat:
description: Body background repeat
example: no-repeat
type: string
backgroundSize:
description: Body background size
example: cover
type: string
type: object
Button:
description: Button block settings
properties:
isFullWidth:
description: Button is full width
example: true
type: boolean
link:
description: Button link
example: https://www.omnisend.com
type: string
text:
description: Button text
example: Shop now
type: string
translationKey:
description: Button translation key - used for internationalization support
example: shop_now
type: string
type: object
ButtonPreset:
description: Button preset for consistent design
properties:
id:
description: Button preset unique identifier
example: primary_button
type: string
name:
description: Button preset name
example: Primary button
type: string
styles:
allOf:
- $ref: '#/components/schemas/ButtonStyle'
description: Button preset styles
type: object
ButtonStyle:
description: Button preset style properties
properties:
backgroundColor:
description: Button background color
example: '#383838'
type: string
border:
description: Button border style
example: '2px solid #BFDCFE'
type: string
borderRadius:
description: Button border radius
example: 0px
type: string
color:
description: Button font color
example: '#FFFFFF'
type: string
fontFamily:
description: Button font family
example: Alegreya, Georgia, Times New Roman, serif
type: string
fontSize:
description: Button font size
example: 16px
type: string
fontStyle:
description: Button font style
example: normal
type: string
fontWeight:
description: Button font weight
example: bold
type: string
letterSpacing:
description: Button letter spacing - spacing between letters
example: 0px
type: string
paddingBottom:
description: Button padding bottom
example: 16px
type: string
paddingLeft:
description: Button padding left
example: 16px
type: string
paddingRight:
description: Button padding right
example: 16px
type: string
paddingTop:
description: Button padding top
example: 16px
type: string
textDecoration:
description: Button text decoration
example: none
type: string
type: object
Column:
description: Column is a single column of the row
properties:
blocks:
description: Column blocks - used to group content into logical blocks
items:
$ref: '#/components/schemas/Block'
type: array
id:
description: Column unique identifier - must be unique within the template
example: 69770b2f7f774c6fb6f57194
maxLength: 24
minLength: 24
type: string
styleProperties:
allOf:
- $ref: '#/components/schemas/StyleProperties'
description: Column style properties - used to configure the column styling
width:
description: Column width - used to set the width of the column
example: 552px
type: string
type: object
Content:
description: Email content
properties:
createdAt:
description: Content created at (read-only)
example: '2021-01-01T01:02:03Z'
readOnly: true
type: string
generalSettings:
allOf:
- $ref: '#/components/schemas/GeneralSettings'
description: Content general settings - global and template level styles
id:
description: Content unique identifier (read-only)
example: 68beca12d2e99b0c8d19fd5e
readOnly: true
type: string
sections:
description: Content sections
items:
$ref: '#/components/schemas/Section'
type: array
updatedAt:
description: Content updated at (read-only)
example: '2021-01-01T01:02:03Z'
readOnly: true
type: string
type: object
CursorsResponse:
description: Cursor pointers for paginating forward and backward through results
properties:
after:
description: Opaque cursor for fetching the next page of results
example: eyJpZCI6ImNhbXAtNDU2In0
type: string
nullable: true
before:
description: Opaque cursor for fetching the previous page of results
example: eyJpZCI6ImNhbXAtMTIzIn0
type: string
nullable: true
type: object
CustomFont:
description: Custom font reference
properties:
id:
description: ID of the custom font
example: 69ca539b38e3c1f5dc035867
maxLength: 24
minLength: 24
type: string
type: object
Discount:
description: Discount block settings. This object configures the offer only — the parts the recipient
sees (code, redeem button, expiry) are separate role-tagged blocks in the parent block's 'components'.
See the notes on the Block 'type' field for the roles each discount block type requires. An offer
needs 'discountType', the value that matches it ('valuePercentage' for a percentage, 'valueFixed'
for an amount off), 'discountConditions', and 'endsIn' for how long it stays valid. 'staticDiscount'
and 'dynamicDiscount' blocks require 'code', 'discountType', 'valuePercentage' and 'discountConditions'.
properties:
appliesToCustomCollectionID:
description: ID of the custom collection that the discount applies to
example: 0
type: integer
appliesToID:
description: ID of the specific resource (product, collection) that the discount applies to
example: 0
type: integer
appliesToResource:
description: Type of resource the discount applies to
example: all
type: string
appliesToSmartCollectionID:
description: ID of the smart collection that the discount applies to
example: 0
type: integer
code:
description: 'Discount code customers use to apply the discount.
In ''discount'' (Shopify, BigCommerce) and ''dynamicDiscount'' (WooCommerce) blocks the code
is not taken from here:
the store issues a unique code per recipient when the email is sent, and it replaces both
this value and the text
of the ''discount_code'' component. Use the placeholder XXXX-XXXX-XXXX in both places — a
literal code written here
is not created in the store, so it is either replaced at send time or, for a brand with automatic
discount
creation switched off, delivered as a code the recipient cannot redeem.
In ''staticDiscount'' blocks (WooCommerce) this is instead the real, fixed code that already
exists in the store.'
example: XXXX-XXXX-XXXX
type: string
combinesWith:
allOf:
- $ref: '#/components/schemas/DiscountCombinesWith'
description: Whether the discount can be combined with other discounts
discountConditions:
description: Conditions that must be met for the discount to apply
example: all_orders
type: string
discountType:
description: 'Type of discount: percentage off, fixed amount off, or shipping discount'
example: percentage
type: string
endsIn:
description: Number of days until the discount ends
example: '14'
type: string
isAppliedOncePerCustomer:
description: When generating a discount code in integrated platforms, the discount can only
be used once per customer
example: false
type: boolean
isDiscountApplied:
description: Whether the discount should be automatically applied to the order
example: true
type: boolean
isItemsOnSaleExcluded:
description: Whether the discount should exclude items that are already on sale
example: false
type: boolean
link:
description: URL link for the discount
example: https://omnisend-inga-qa7-new.myshopify.com
type: string
minimumOrderAmount:
description: Minimum order amount required for the discount to apply
example: '50'
type: string
offerText:
description: Text displayed to customers when they apply the discount
example: Get 15% off your order
type: string
title:
description: Title of the discount
example: Summer Sale
type: string
usageLimit:
description: Maximum number of times the discount can be used
example: '100'
type: string
validUntil:
description: Date and time when the discount expires
example: '2026-02-09T06:42:35.350Z'
type: string
validUntilFormat:
description: Format of the expiration date
example: MMM DD, YYYY
type: string
validUntilFormatted:
description: Formatted expiration date
example: Feb 09, 2026
type: string
valueFixed:
description: Fixed value of the discount
example: '10'
type: string
valuePercentage:
description: Percentage value of the discount
example: '15'
type: string
type: object
DiscountCombinesWith:
description: Discount combines with settings
properties:
isOrderDiscountsCombined:
description: Whether the discount can be combined with order-level discounts
example: true
type: boolean
isProductDiscountsCombined:
description: Whether the discount can be combined with product-specific discounts
example: true
type: boolean
isShippingDiscountsCombined:
description: Whether the discount can be combined with shipping discounts
example: true
type: boolean
type: object
DynamicList:
description: Dynamic list settings for repeating content blocks
properties:
columnCount:
description: Number of columns in the list layout
example: 3
type: integer
layout:
description: Layout type for the list items
example: grid
type: string
listPath:
description: Data path for the list items source
example: items
type: string
repetitionCount:
description: Maximum number of items to display
example: 5
type: integer
type: object
FieldError:
description: Field-level validation error details
properties:
code:
description: Machine-readable error code
example: required
type: string
field:
description: 'Name of the field that caused the error, as a dot-separated path using the field
names of
the request schema. Array indices are not included: a fault inside sections[0].rows[2] is
reported as "sections.rows".'
example: sections.rows.columns.blocks.styleProperties.borderRadius
type: string
message:
description: Human-
# --- truncated at 32 KB (73 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/omnisend/refs/heads/main/openapi/omnisend-emailcontent-api-openapi.yml