orbotodocs
orboto Mail

Templates

Store subject + body server-side and send by referencing a template id, with variable validation and version history.

A template is a subject and body stored on your orboto Mail account instead of inside your application code. This matters for two reasons: you can update the wording of a transactional email (a welcome message, a password reset) without a deploy, and a template can validate its own variables so a caller that forgets one gets a clear error instead of a half-rendered email reaching a customer.

Create a template

curl https://mail.orboto.io/api/v1/templates \
  -X POST \
  -H "Authorization: Bearer oms_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "welcome",
    "subject": "Welcome to Acme, {{name}}!",
    "bodyHtml": "<h1>Hi {{name}}</h1><p>Activate your account: <a href=\"{{activationUrl}}\">click here</a>.</p>",
    "bodyText": "Hi {{name}}, activate your account: {{activationUrl}}",
    "variablesSchema": {
      "type": "object",
      "required": ["name", "activationUrl"],
      "properties": {
        "name": { "type": "string" },
        "activationUrl": { "type": "string", "format": "uri" }
      }
    }
  }'

Placeholders use {{variableName}} syntax in both subject and the body fields. An unknown placeholder (a typo, or a variable you forgot to pass) renders as an empty string rather than failing the send - so a mistake shows up as missing text in the delivered email, not a crash. Values substituted into bodyHtml are HTML-escaped automatically, so a variable containing <script> or similar can't inject markup into the rendered page.

variablesSchema is optional but recommended. It's a small subset of JSON Schema: required (array of variable names that must be present), and per-variable type (string/number/integer/boolean), an optional format (uri or email, checked with a light regex, string variables only), and an optional enum of allowed values. A template created without a schema accepts any variables you send it.

The response echoes the stored template with its id, plus createdAt/updatedAt. Every create and update also appends a version snapshot server-side, so you (or the account.orboto.io/mail/templates dashboard) can see the template's edit history.

Send with a template

curl https://mail.orboto.io/api/v1/send \
  -X POST \
  -H "Authorization: Bearer oms_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme Support <support@yourdomain.example>",
    "to": "user@example.com",
    "templateId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "variables": { "name": "Alice", "activationUrl": "https://app.example.com/activate/abc123" }
  }'

Pass templateId and variables to POST /v1/send (or as one entry in a batch send) instead of html/text

  • the two are mutually exclusive in the same call. subject is optional when a template is used: if you omit it, the template's own subject (with its own {{}} placeholders resolved from variables) is used. If variables fails the template's schema, the send returns 400 template_variable_validation with one message per failed check, and nothing is sent.

Managing templates

Method + pathPurpose
GET /v1/templatesList every template on the account, most recently updated first.
GET /v1/templates/:idFetch one template, including its variablesSchema.
POST /v1/templatesCreate (shown above).
PATCH /v1/templates/:idUpdate any subset of name, subject, bodyHtml, bodyText, variablesSchema.
DELETE /v1/templates/:idRemove a template. Existing oms_sends history rows that used it are unaffected.

Templates are private to your account - there is no shared or cross-account template library.

Troubleshooting

SymptomFix
400 template_variable_validationRead the message field - it lists every failing variable by name and what's wrong (missing, wrong type, bad format, not in the enum). Fix the caller's variables payload.
A placeholder like {{usrname}} shows up literally, or renders blankAn unknown placeholder renders as empty, it doesn't error. Check the variable name matches exactly (case-sensitive) between the template body and your variables object.
404 template_not_found when sendingThe templateId doesn't exist on this account, or belongs to a different account/key. Confirm with GET /v1/templates.
I need conditionals / loops in a templateThe renderer only does flat {{variableName}} substitution - no logic. Build any conditional content into the variables payload before sending (e.g. pre-render an HTML fragment) instead.

On this page