Skip to main content

Client API Reference

This page lists every HTTP endpoint exposed by the Email Templates feature and shows how to call it. For the higher-level concepts (templates, fragments, contexts, MJML + Fluid, translations, versioning) see the feature overview.

All endpoints require the standard authentication headers (Authorization: Bearer …) and Content-Type: application/json. Authorization uses the EmailTemplates access item; the access type (View / Add / Edit / Delete) is shown per endpoint.

There are two route groups:

  • /api/email/templates — full templates
  • /api/email/fragments — reusable MJML fragments referenced from templates
tip

Each version of a template is its own row with its own numeric id. CRUD, send and "create new version" are addressed by id; the version list and delete endpoints are addressed by templateKey. Preview is template-independent — it takes the MJML in the request body, not an id.


Templates

GET /api/email/templates

Returns every template row in the system (every version of every template).

GET /api/email/templates/{id}

Returns a single template row by numeric id.

  • Access: EmailTemplates.View
  • Response: 200 OKEmailTemplateViewDto
  • Errors: 404 if no row with that id exists.

POST /api/email/templates

Creates a brand-new template. The new row is inserted at version = 1 with whatever status was supplied (defaults to Draft). The MJML source is validated and compiled on save; any referenced fragments must already exist.

  • Access: EmailTemplates.Add

  • Body:

    {
    "templateKey": "order-scheduled-for-delivery",
    "templateContextKey": "OrderScheduledForDelivery",
    "name": "Order scheduled for delivery",
    "description": "Sent when a customer order is dispatched.",
    "mjmlSource": "<mjml>…</mjml>",
    "statusId": 81587
    }
    FieldRequiredNotes
    templateKeyyesLowercase alphanumeric + hyphens, 2–100 chars. Must not collide with any existing template key.
    templateContextKeynoThe data context the template binds to (e.g. Event, OrderScheduledForDelivery). Must match an existing context known to the server. Omit it when the MJML has no model placeholders to resolve.
    nameyesDisplay name.
    descriptionnoUp to 1000 chars.
    mjmlSourceyesMJML markup, may reference fragments.
    statusIdyesDictionaryItem id from the Publish status group of the Email templates configuration dictionary (81587 = Draft, 81588 = Published).
  • Response: 201 CreatedEmailTemplateViewDto. Version starts at 1.

  • Errors: 400 for invalid key, duplicate key, missing fragment, MJML compile error, or Fluid template error.

PUT /api/email/templates/{id}

Updates the template row identified by id in place. templateKey and version are fixed for the life of a row — change them by creating a new version (see below). Everything else is mutable. The MJML source is re-validated on save.

POST /api/email/templates/{id}/versions

Creates a new Draft version by copying the row identified by id. The new row inherits the source's templateKey, templateContextKey, name, description, and mjmlSource. Its version is set to max(version) + 1 across all rows sharing that templateKey, and its status is forced to Draft.

At most one Draft can exist per template key — if one already exists, this call is rejected.

  • Access: EmailTemplates.Add
  • Body: none
  • Response: 201 CreatedEmailTemplateViewDto for the newly inserted draft row.
  • Errors: 404 if the source id does not exist; 400 if a Draft already exists for that template key.

GET /api/email/templates/{templateKey}/versions

Lists every version (any status) for the given template key, ordered by version descending.

DELETE /api/email/templates/{templateKey}

Soft-deletes either a single version of a template or every version of it. Exactly one selector must be supplied: a version query parameter, or deleteAllVersions=true.

  • Access: EmailTemplates.Delete

  • Query parameters:

    NameTypeNotes
    versionint?The single version to delete.
    deleteAllVersionsboolWhen true, every version of the template key is soft-deleted.
  • Response: 204 No Content

  • Errors:

    • 400 if neither or both selectors are supplied.
    • 404 if no rows match.

POST /api/email/templates/preview

Renders the specific template row identified by id to final HTML without sending an email. The id can refer to any version (Draft or Published), so the editor can preview the version it is currently working on.

  • Access: EmailTemplates.View

  • Body:

    {
    "mjmlSource": "<mjml>…</mjml>",
    "templateContextKey": "OrderScheduledForDelivery",
    "data": {
    /* model fields matching templateContextKey */
    },
    "locale": "en-US"
    }
    FieldRequiredNotes
    mjmlSourceyesThe MJML being authored. May reference fragments, which must already exist.
    templateContextKeynoThe data context the MJML binds to (e.g. Event). Must match an existing context; drives the data model used for Fluid. Omit it when the MJML has no model placeholders — it is then rendered with no model.
    datanoJSON object matching templateContextKey. If omitted, the server fills in default sample data so you can still see a render. Ignored when no templateContextKey is supplied.
    localeyesLocale code used for the t translation filter (e.g. en-US, el-GR).
  • Response: 200 OK

    {
    "html": "<!doctype html>…"
    }
  • Errors: 400 if mjmlSource is empty, templateContextKey is supplied but unknown, a referenced fragment is missing, the MJML fails to compile, or data fails Fluid rendering.

POST /api/email/templates/{id}/send

Testing endpoint: renders the specific template row identified by idregardless of status, including Draft — and queues the resulting HTML for delivery. The endpoint returns as soon as the message is queued; actual SMTP delivery happens asynchronously via SparkPost.

Use this to dispatch a draft to a real inbox while still iterating on it; production sends are issued from backend code that resolves templateKey → latest Published version.

  • Access: EmailTemplates.Edit

  • Body:

    {
    "data": {
    /* model fields matching the template's context */
    },
    "locale": "en-US",
    "to": ["alice@example.com", "bob@example.com"],
    "subject": "Your order is on its way"
    }
    FieldRequiredNotes
    datanoSame shape as preview. Omit for default sample data (mostly useful in dev).
    localenoLocale for translations. Falls back to the template's default if omitted.
    toyesAt least one recipient. Duplicates are removed automatically.
    subjectyesEmail subject line.

    The sender identity is fixed server-side (info@alerts.people-t.com / "People Omni") and cannot be overridden by the caller — there are no fromEmail / fromName / replyTo fields.

  • Response: 202 Accepted — empty body. The email has been queued, not yet delivered.

  • Errors: 404 if the row id does not exist; 400 for an empty to, empty subject, or model/context mismatch.

:::note Async delivery Because the send is asynchronous, the endpoint does not return a SparkPost transmission id. If you need delivery confirmation, listen on the existing email-webhook / table-storage transmission log. :::


Fragments

Fragments are reusable MJML snippets referenced from templates. They support parameters (passed in via Fluid) and come in two types: Component (rendered MJML) and Style (stylesheet-only injection).

GET /api/email/fragments

Returns every fragment.

GET /api/email/fragments/{id}

Returns a single fragment by id.

POST /api/email/fragments

Creates a new fragment.

  • Access: EmailTemplates.Add

  • Body:

    {
    "fragmentKey": "cta-button",
    "name": "CTA Button",
    "description": "Branded call-to-action button.",
    "fragmentType": 0,
    "mjmlSource": "<mj-button background-color=\"#0066cc\" href=\"{{ href }}\">{{ text }}</mj-button>",
    "parameters": [
    { "name": "text", "default": "Click here" },
    { "name": "href" }
    ]
    }
    FieldRequiredNotes
    fragmentKeyyesStable identifier used from templates.
    nameyesDisplay name.
    descriptionnoOptional notes for editors.
    fragmentTypeno0 = Component, 1 = Style. Defaults to Component.
    mjmlSourceyesMJML markup. Can reference {{ parameter }} placeholders.
    parametersnoDeclared parameters with optional defaults. A parameter without a default must be supplied by the caller at template-time.
  • Response: 201 CreatedEmailTemplateFragmentViewDto

  • Errors: 400 for invalid input.

PUT /api/email/fragments/{id}

Updates a fragment. Templates that reference it will pick up the change on next render (with cache invalidated when any referenced fragment changes).


OData

For list/filter/sort scenarios there is an OData endpoint on templates:

  • GET /api/odata/email-templates — supports $filter, $select, $orderby, $top, $skip, $expand.
  • GET /api/odata/email-templates({id}) — single entity.

The shape is the same as EmailTemplateViewDto. Every version of every template is a separate row in this feed.


Schemas

EmailTemplateViewDto

FieldTypeNotes
idintAuto-generated row id. Unique per version.
templateKeystringStable identifier. Shared across every version of the same template.
templateContextKeystringThe data context this template binds to.
namestringDisplay name.
descriptionstring?Optional.
mjmlSourcestringMJML markup.
statusreferencePublish status dictionary item, e.g. { "id": 81588, "name": "Published" }.
versionintVersion number for this row. (templateKey, version) is unique.
createdAt / modifiedAtdatetime?Audit timestamps.
creator / modifieruser?Audit user info.

EmailTemplateEditDto

The mutable surface of an existing row. templateKey and version are fixed for the row and are not part of this DTO.

FieldTypeNotes
templateContextKeystring?Optional. Must match an existing context when supplied; omit it when the MJML has no model placeholders.
namestringRequired. Display name.
descriptionstring?Up to 1000 chars.
mjmlSourcestringRequired. Re-validated and re-compiled on every save.
statusIdintDictionaryItem id from the Publish status group. Set to 81588 (Published) to publish a Draft row.

EmailTemplateVersionDto

Returned by the "list versions" endpoint.

FieldTypeNotes
idintRow id of this version.
versionintVersion number.
statusreferencePublish status dictionary item, e.g. { "id": 81587, "name": "Draft" }.

EmailTemplateFragmentViewDto

FieldTypeNotes
idintAuto-generated.
fragmentKeystringStable identifier.
namestringDisplay name.
descriptionstring?Optional.
fragmentTypeint0 = Component, 1 = Style.
mjmlSourcestringMJML markup.
parametersarray?See FragmentParameterDefinitionDto.
createdAt / modifiedAtdatetime?Audit timestamps.
creator / modifieruser?Audit user info.

EmailTemplateFragmentEditDto

All fields of EmailTemplateFragmentAddDto, plus id (must match route).

FragmentParameterDefinitionDto

FieldTypeNotes
namestringParameter name as used in {{ name }}.
defaultstring?Optional default value. If omitted, callers must supply this parameter.

Typical client flows

Edit a published template through a new draft

  1. GET /api/email/templates/{templateKey}/versions to find the currently-published row.
  2. POST /api/email/templates/{id}/versions with that row's id — server returns a fresh Draft row at the next version number.
  3. PUT /api/email/templates/{draftId} to iterate on the draft (name, description, MJML, context, statusId).
  4. POST /api/email/templates/preview with the draft's mjmlSource + templateContextKey to verify the result in the editor.
  5. POST /api/email/templates/{draftId}/send to dispatch the draft to a real inbox for end-to-end QA.
  6. PUT /api/email/templates/{draftId} once more with statusId: 81588 (Published) to publish.

Render a preview while editing a template

  1. POST /api/email/templates/preview with the in-progress mjmlSource, the templateContextKey, optional sample data, and a locale — display the returned html in an iframe. No template needs to exist yet.

Delete a template

  • One specific version: DELETE /api/email/templates/{templateKey}?version=2.
  • Every version: DELETE /api/email/templates/{templateKey}?deleteAllVersions=true.

Create a template that reuses fragments

  1. POST /api/email/fragments for each shared snippet (button, header, row…).
  2. POST /api/email/templates referencing those fragment keys from the template's MJML.
  3. POST /api/email/templates/preview with that MJML + templateContextKey to verify.