NorthRelayNorthRelay
Features

NorthRelay Studio

One place for email templates and brands — visual or HTML editing, versioned releases, brand previews, and the same templates from the dashboard, the API, SDKs, MCP and embedded apps

NorthRelay Studio

NorthRelay Studio is where your email templates and brands live. Every template, whether you build it in the dashboard, adopt it from the gallery or create it from code, is a versioned design: you edit a draft, review it, and publish an immutable release that sends use. Studio is included from the Micro plan ($12/mo).

Open it from the sidebar: Studio → Overview, Templates, Brands, Assets, Applications and Activity.

What you get

CapabilityWhat it means for you
TemplatesBuild visually with blocks or write HTML with Handlebars variables. Start blank or from the gallery (authentication, notifications, billing, marketing).
BrandsColours, logo, fonts, sender, compliance contact, footer, social links, custom variables and the unsubscribe page. Every template reads them as {{theme.*}}. Contrast checks warn when text would be hard to read.
PreviewRendered by the same engine that sends: desktop, mobile, simulated dark mode and plain text, with sample data from the variable schema or your own values. Preview any template with another brand before you switch.
Review & publishA field-by-field diff against the live release before you publish. Drafts autosave and never affect live mail.
ReleasesEach publish is an immutable snapshot. Restore any earlier release in one click.
UsageSee which campaigns use a template and how many messages it sent, and which templates and campaigns use a brand.
DeliveriesEvery send through a template, from the API or Studio, with its delivery events.
Test sendsSend yourself a test from a verified sender, safely retried with an idempotency key.
AssetsUpload a logo (PNG, JPEG or WebP up to 700 KiB). NorthRelay resizes it for email and serves it from an immutable HTTPS URL.
ApplicationsProducts that send through NorthRelay (for example Alteriom Command Center) keep their own templates and brands under an application key, reached with a scoped nr_app_ credential.

Account templates and application templates

Your own templates, the ones you create in the dashboard, belong to the reserved application account. Products can own templates under their own application key. The two differ in how they treat brands and variables:

Account templates (account)Application templates (e.g. command-center)
BrandUses the bound brand live: edit the brand and the next send uses it.The brand is frozen in each release. After a brand change, the brand editor lists the templates to publish again and can publish them for you.
VariablesLenient: a missing variable renders empty, extra variables are ignored.Strict: required variables must be present, unknown variables are refused.
SenderOptional on the template; the brand sender is the default, and a send can choose another verified sender.Must be one of the credential's allowed senders.

Sending with a template

Use the template id with the email API. Nothing changes if you already send this way:

curl -X POST https://app.northrelay.ca/api/v1/emails/send \
  -H "Authorization: Bearer $NORTHRELAY_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "from": { "email": "hello@acme.example", "name": "Acme" },
    "to": [{ "email": "ana@example.com" }],
    "content": { "templateId": "tmpl_123" },
    "variables": { "first_name": "Ana" }
  }'

The send uses the template's live release. A retired template is refused with TEMPLATE_RETIRED, a template that was never published with TEMPLATE_NOT_PUBLISHED, and missing required variables with MISSING_TEMPLATE_VARIABLES; each error names the fix.

Campaigns pick a template in the campaign wizard and render it with the contact's details, the brand and the unsubscribe links.

From code

Everything in Studio is available through /api/v1/designs, the SDKs and the MCP server.

# Create a draft for your application
curl -X POST https://app.northrelay.ca/api/v1/designs \
  -H "Authorization: Bearer $NORTHRELAY_APP_KEY" -H "Content-Type: application/json" \
  -d '{
    "applicationKey": "command-center",
    "key": "daily-digest",
    "locale": "en",
    "draft": {
      "name": "Daily digest",
      "subject": "{{title}} — {{date}}",
      "html": "<h1>{{title}}</h1>{{#each stories}}<p><a href=\"{{url}}\">{{headline}}</a></p>{{/each}}",
      "category": "NOTIFICATION",
      "variables": {
        "title": { "type": "string", "required": true, "example": "Digest" },
        "stories": { "type": "array", "items": { "headline": { "type": "string" }, "url": { "type": "string", "format": "url" } } }
      }
    }
  }'

# Publish revision 1, then send the live release with an idempotency key
curl -X POST https://app.northrelay.ca/api/v1/designs/$DESIGN_ID/publish \
  -H "Authorization: Bearer $NORTHRELAY_APP_KEY" -H "Content-Type: application/json" \
  -d '{ "expectedRevision": 1 }'

curl -X POST https://app.northrelay.ca/api/v1/designs/$DESIGN_ID/send \
  -H "Authorization: Bearer $NORTHRELAY_APP_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: digest-2026-10-08" \
  -d '{ "to": [{ "email": "ops@example.com" }], "variables": { "title": "Digest", "date": "8 Oct", "stories": [] } }'
import { NorthRelayClient } from '@northrelay/sdk';
const nr = new NorthRelayClient({ apiKey: process.env.NORTHRELAY_API_KEY! });

const { data: usage } = await nr.designs.usage(designId);           // campaigns and send counts
await nr.designs.preview(designId, { sample: true, brandId });       // try another brand
const { data: brand } = await nr.designs.brandUsage(brandId);        // what a brand change affects
await nr.designs.uploadAsset({ imageBase64 });                       // logo for a brand

Every response is { success: true, data } or { success: false, error: { code, message } }. Writes carry expectedRevision (designs) or expectedUpdatedAt (brands), so two editors get a 409 REVISION_CONFLICT instead of overwriting each other.

API surface

MethodPathPurpose
GET/api/v1/capabilitiesPermissions, application and sender restrictions, plan capacity
GET, POST/api/v1/designsList templates (filters, cursor) / create a draft
GET, PATCH, DELETE/api/v1/designs/{id}Read / replace the draft (expectedRevision) / delete a template that never sent
POST/api/v1/designs/{id}/previewRender the draft, the live release or a version; brandId previews another brand
POST/api/v1/designs/{id}/publishPublish expectedRevision
POST/api/v1/designs/{id}/rollbackCopy an earlier version into a new release
GET/api/v1/designs/{id}/releasesRelease history; ?version= for a full snapshot
POST/api/v1/designs/{id}/sendSend the live release (Idempotency-Key required)
GET/api/v1/designs/{id}/deliveriesSends through this template and their events
GET/api/v1/designs/{id}/usageCampaigns using the template, send counts
PATCH/api/v1/designs/{id}/lifecycleRetire or restore, with an optional replacement
POST/api/v1/designs/{id}/brandBind a brand
POST/api/v1/designs/{id}/syncCompare with or apply updates from the gallery source
GET, POST/api/v1/designs/catalogBrowse the gallery and shared templates / inspect one
POST/api/v1/designs/catalog/adoptAdopt a starter (asBlocks for the visual editor)
GET, POST/api/v1/designs/brandsList / create brands
GET, PATCH, DELETE/api/v1/designs/brands/{id}Read / update (expectedUpdatedAt) / delete an unused brand
GET/api/v1/designs/brands/{id}/usageTemplates and campaigns using the brand
POST/api/v1/designs/brands/{id}/defaultMake an account brand the default
GET, PUT, DELETE/api/v1/designs/brands/{id}/tracking-domainCustom tracking domain (POST …/verify checks the CNAME)
GET, POST, DELETE/api/v1/designs/assetsList / upload / delete images
GET, POST/api/v1/designs/manifestExport (with a version that changes when any draft changes), plan or atomically apply drafts; publish: true then publishes each changed entry

New releases render with handlebars-email-v2: values are escaped, template sources are checked on save and publish (no script, iframe, form, event handlers or javascript: links), and MJML styles and Outlook conditional comments are kept.

The TypeScript and Python SDKs expose these as client.designs, and the MCP server as the *_email_design*, *_email_brand* and *_email_asset* tools.

Installing templates into another account

A product that sends through its users' own NorthRelay accounts can ship its templates as a manifest: export the application's manifest from the product's account, then apply it with the user's credential into their account (dryRun: true to show the plan, then dryRun: false, publish: true to install and publish in one call). The export's version tells you when an installed copy is behind.

Embedding Studio in your product

@northrelay/studio-react renders the same Studio screens (template library, workspace, brands) inside another React app. Your server proxies the Studio API with an application credential, so no NorthRelay key reaches the browser. Alteriom Command Center uses it.

Legacy APIs

/api/v1/templates and /api/v1/brand-theme keep working until 30 April 2027 and return Deprecation, Sunset and Link: rel="successor-version" headers. Every existing template is now a Studio template with the same id, so templateId values in your code stay valid. Move template and brand management to /api/v1/designs.

Plans

FreeStarterMicroProScale
Studio access––YesYesYes
Templates––25100500
Brands––31025
Application credentials––YesYesYes

See Plans & Pricing for the full ladder.

On this page