Custom templates
- Written for
- + Written for
- Deprecated
- + Deprecated
- Applies to
- + Applies to
Custom templates
A template tells Shippified two things about a kind of message: how to recognise it (detection rules) and where to find each order detail in it (field mappings). Shippified includes built-in templates for common monitor bots and major retailers. When a bot or retailer isn't covered, or isn't read the way you want, you can build your own from a real sample.
Custom templates run through the same engine as the built-ins. Anything a built-in template can read, a custom one can too.
The Templates page
Open Templates in the sidebar. At the top:
Webhook / Email switches between templates for Discord webhook payloads and templates for emails.
Re-run parsing rebuilds your existing orders using your current templates (see Applying changes to existing orders).
Build template opens the builder.
Below that are two sections:
Section | What's in it |
|---|---|
Your templates | The custom templates in your workspace. Each card shows the event type, how many rules and mappings it has, and the first few mappings. Use the pencil icon to edit and the trash icon to delete. |
Built-in | Templates maintained by Shippified, marked Live. You can't edit these, but you can override them with a custom template (custom templates are tried first). |
Note: Deleting a custom template happens immediately, without a confirmation step. Bots that had it pinned show missing and go back to automatic detection. Existing orders keep their values until you re-run parsing.
Which template wins
Every incoming payload is checked against templates in this order:
Webhooks only: the template pinned on the receiving bot. It is always used, whether or not its rules pass.
Your custom templates of the matching kind (webhook or email), newest first. Your templates on the Templates page lists them in this same order, and the order stays the same from one message to the next.
Built-in templates.
The first template whose detection rules all pass is used. After that, Shippified runs a generic pass that fills in any field the template didn't extract, such as quantity, tracking number or carrier. You only need to map what's specific to the message.
For email, an inbox can be limited to certain templates using Templates this source parses against in its settings (see Connect email). The chosen templates are then tried in the order you set.
Important: A template with no detection rules only runs when a Discord bot pins it as its Parser template. It's never chosen automatically, and that includes email: an email template with no rules never matches, even if an inbox lists it under Templates this source parses against. Always give email templates at least one rule, such as a sender filter. The builder reminds you of this while the rule list is empty.
The builder
Click Build template, or the pencil icon on one of your templates. The builder has a settings column on the left and an Extraction map column on the right.
Template settings
Field | Options |
|---|---|
Template name | Shown in the library, in the bot's Parser template list and on orders. |
Source | Webhook JSON or Email HTML / text. |
Event type | Other, Order placed, Order shipped, Order update, Order delivered, Order canceled. |
Event type fixes the lifecycle event for every message this template handles, and that drives the order's status. Choose Other when one template covers several events, which is common for monitor bots that send the same layout for everything. Shippified then works out the event from the wording ("shipped", "delivered", "canceled", "out for delivery", "successful checkout" and so on).
Note: Choose the Source before you start mapping. Changing it replaces your mappings with the starter mappings for the new source, and if you've edited the sample, Shippified asks before replacing it too (Replace the sample payload?). Once a template is saved, its source is fixed: when you edit it, leave Source as it is. To read the other kind of message, build a new template.
There's no store picker in the builder. Shippified works out the store from the sender's address (email), from the embed text (webhooks), or from a store mapping. It currently recognises Target, Walmart, Amazon and Best Buy. Orders from other retailers are filed under Unknown Store. A template created through the API can have a fixed store; editing it in the builder keeps that store.
The sample payload
Sample payload is the reference message your rules and mappings are tested against.
Webhook: paste the JSON body your bot posts, usually
{ "embeds": [ ... ] }. You can copy it from a bot's activity log, or click Load from Discord to use an embed captured with the embed copier.Email: paste the raw email, including headers. In Gmail, use Show original. At minimum, include
From:andSubject:lines, then a blank line, then the HTML or text body.
Use one sample per template. If a retailer's "order placed" and "order shipped" emails look different, build two templates.
Detection rules
Detection rules decide whether the template applies. Click Add rule to add one. Each rule has a Type, a Selector, an Operator and a Value. Email rules also have a Scope.
As you edit, each rule shows matched or no match against the sample, and Resolved against sample: shows the exact value the selector found. Use it to check that your selector is reading what you expect.
Selector types
Type (UI label) | Selector example | What it reads |
|---|---|---|
JSON path |
| A value in the webhook JSON. Use dots between keys and |
Embed field name |
| Webhook: the embed field with this name, ignoring case. Otherwise, a |
Regex capture |
| Searches the message and uses the first capture group, or the whole match if there's no group. |
Operators
Operator | Passes when |
|---|---|
equals | The resolved value equals Value exactly (ignoring case). |
contains | The resolved value contains Value (ignoring case). |
regex | Value is a regular expression that matches the resolved value (ignoring case). |
exists | The selector found any non-empty value. Value isn't used. |
A rule whose selector finds nothing fails, except that exists is simply false. All rules must pass for the template to apply.
Scope (email only)
Scope | Looks at |
|---|---|
header | The decoded |
body | The email body: first the HTML, then its plain-text version. |
auto | header when the selector starts with a header name such as |
For email templates, Filter by sender above the rule list is a shortcut. Type part of the sender address (for example @mail.example-shop.com) and Shippified adds a hidden rule: "From header contains this text". Leave it empty for no sender filter.
Tip: Header lines are joined in the order From, To, Subject, Date. A regex that starts with
^only matches at the very start (theFrom:line), so^Subject:won't match. WriteSubject:\s*([^\n]+), or(?:^|\n)Subject:\s*([^\n]+)as the builder's placeholder suggests, or use Embed field name with the selectorSubject.
Field mappings
Mappings in the Extraction map column say where each order detail comes from. Click Add mapping, choose a target field and a selector type, then enter the selector. Every mapping shows its Extracted value from the sample. Click Preview to refresh them all.
Target | Use it for |
|---|---|
| The retailer's order number. Messages with the same order number are merged into one order. |
| The product name. |
| Customer, profile or account name. |
| Money amounts. The cost on the order comes from |
| Units. Only the digits are used. |
| Shipping details. If you don't map a carrier, it's detected from the tracking number. |
| Product variant details. |
| Links shown on the order. |
| When the event happened, if the message says. |
| Only works if the value names a recognised retailer. |
| Only used when Event type is Other. The value can be an event name ( |
| Any extra value. Give it a custom key, and it's stored on the order under that name. |
How mappings behave:
Several mappings for one target act as fallbacks. The first one that returns a value wins, so put the most specific one first.
Regex mappings search the email HTML first, then the plain-text version, then the header lines. Matching always ignores case, and
.also matches line breaks, so prefer[^\n<]+over.*to stop at the end of the value.Values are cleaned automatically. HTML tags and entities are removed, Discord formatting (
||spoiler||,**bold**,__underline__, backticks) is removed, and extra spaces are collapsed.<strong>$49.99</strong>becomes$49.99.
Tip: Writing a regex for an HTML email? Write it against how the email reads as plain text (the
Label: valuewording). If it doesn't match the raw HTML, Shippified tries it again on the plain-text version.
The "In production" panel
Under the mappings, In production runs the real parser on your sample, with your draft tried ahead of your saved templates. It never creates or changes an order, so it's the place to test a template without touching your data. (The Import an email by hand panel under Links → Emails is different: it runs the same parser but adds the result to your orders.) It tells you:
This template handles it: your draft's rules pass, so it would handle this message.
Handled by name (marked (built-in) if it's a built-in): your draft's rules don't all pass, so another template would handle it.
No template matches — generic parsing: nothing matched, so only the generic pass would run.
Ignored — not recognised as order mail (email only): this message wouldn't become an order at all.
It also previews the order that would be created: Status, Event, Store, Order #, Item, Total, Qty and Tracking. A dash means that value is missing.
Note: The panel doesn't take bot pins or inbox template lists into account. A pinned template always wins for that bot, whatever the panel shows. It also tries your draft first, while live intake tries custom templates newest first. If you're editing an older template and a newer one also matches the sample, the newer one wins in production.
Saving and validation errors
Click Save template (or Save changes when editing). Rules and mappings with an empty selector are dropped when you save. An invalid regular expression stops the save and shows an error above the button, for example:
Rule 2 selector is not a valid regex: Invalid regular expression: /Order (#/is: Unterminated group
Rule 3 value is not a valid regex: Invalid regular expression: /*shipped/is: Nothing to repeat
Mapping 1 (orderNumber) is not a valid regex: Invalid regular expression: /[A-Z/is: Unterminated character classThe part between the slashes is your pattern. The message after it tells you what's wrong: an unclosed ( or [, or a * or + with nothing in front of it. To match those characters literally, put a backslash before them, for example \( or \*.
If you don't use Filter by sender, the rule number in an error matches the Rule N label in the builder. If you do, the error counts the sender filter as rule 1, so its number is one higher than the label: an error about Rule 2 refers to the rule labelled Rule 1. Mapping numbers always match the mapping's position in the list.
Worked example 1: an email template for a new retailer
A fictional retailer, Northwind Outfitters, sends this order confirmation:
From: Northwind Outfitters <[email protected]>
To: [email protected]
Subject: Your Northwind order NW-448812 is confirmed
<html><body>
<h1>Thanks for your order!</h1>
<p>Order number: <strong>NW-448812</strong></p>
<p>Item: <strong>Trail Runner 2 Jacket - Size M</strong></p>
<p>Quantity: 2</p>
<p>Order total: <strong>$189.98</strong></p>
</body></html>Click Build template. Set Source to Email HTML / text, Template name to "Northwind — placed" and Event type to Order placed.
Paste the email into Sample payload.
In Filter by sender, enter
@mail.northwind-outfitters.example.The builder starts with a rule that checks for a different sender. Remove it with its trash icon.
Add a subject rule:
Type
Selector
Operator
Value
Scope
Regex capture
Subject:\s*([^\n]+)contains
is confirmedheader
Replace the starter mappings with these:
Target
Type
Selector
orderNumberRegex capture
Order number:\s*(NW-\d+)itemSummaryRegex capture
Item:\s*([^\n<]+)totalRegex capture
Order total:\s*(\$[\d,.]+)Check that In production reads This template handles it, with order
NW-448812, the jacket as the item,$189.98as the total and a quantity of 2. You didn't map quantity: the generic pass foundQuantity: 2.Click Save template.
Because Northwind isn't a recognised retailer, the order's store is Unknown Store. Map itemSummary whenever you can: an order with an unknown store and no item is flagged as Issue for review.
Worked example 2: a second template for shipping emails
The same retailer's shipping email has the subject "Your Northwind order NW-448812 has shipped" and a line reading Tracking number: 1Z999AA10123456784. Build a second template:
Event type: Order shipped
Filter by sender:
@mail.northwind-outfitters.exampleRules:
Type
Selector
Operator
Value
Scope
Regex capture
Subject:\s*([^\n]+)contains
has shippedheader
Regex capture
Tracking number:\s*(\w+)exists
body
Mappings:
orderNumberwith the same regex as before, andtrackingNumberwithTracking number:\s*(\w+).
The shipping email carries the same order number, so it's merged into the order from example 1. That order moves to shipped, gets the tracking number, and its carrier is detected automatically. Each template's subject rule keeps it from claiming the other email.
Worked example 3: a Discord monitor embed
A fictional monitor, Lumen, posts this webhook:
{
"username": "Lumen",
"embeds": [{
"title": "Successful Checkout",
"author": { "name": "Lumen Monitors" },
"thumbnail": { "url": "https://cdn.example.com/p/earbuds.png" },
"fields": [
{ "name": "Site", "value": "Target" },
{ "name": "Product", "value": "**Wireless Earbuds Pro**" },
{ "name": "Price", "value": "$129.99" },
{ "name": "Qty", "value": "1" },
{ "name": "Order", "value": "||912000111222||" },
{ "name": "Profile", "value": "Main 01" }
],
"footer": { "text": "Lumen Monitors v3.2" }
}]
}Click Build template with the Webhook tab selected. Set Source to Webhook JSON and Event type to Order placed.
Paste the JSON, or click Load from Discord and pick the captured embed.
Set these rules:
Type
Selector
Operator
Value
JSON path
embeds[0].footer.textcontains
LumenJSON path
embeds[0].titleregex
success(ful)? checkoutSet these mappings:
Target
Type
Selector
orderNumberEmbed field name
OrderitemSummaryJSON path
embeds[0].fields[1].valuetotalEmbed field name
PricestoreEmbed field name
SitecustomerNameEmbed field name
ProfileimageUrlJSON path
embeds[0].thumbnail.urlCheck the Extracted values. The spoiler bars around the order number and the bold markers around the product name are removed, and
Targetis recognised as the store.Save. Then go to Links → Webhooks, edit the Lumen bot and choose "your template name · custom" under Parser template. See Connect Discord monitor bots.
Tip: Embed field name selectors keep working if the bot changes the order of its fields.
fields[1]-style JSON paths don't. Use JSON paths for values that aren't in fields, such as the title, footer, author or thumbnail.
Editing templates
Click the pencil icon on a template card, change it and click Save changes. Changes apply to new messages straight away. Editing doesn't change a template's place in the order: it's still ranked by when it was created. Settings the builder doesn't show, such as a fixed store set through the API, are kept.
Applying changes to existing orders
Every email and webhook payload Shippified receives is stored. After you create or change templates, click Re-run parsing on the Templates page to rebuild your existing orders from their original messages. Shippified reports the result, for example "Re-parsed 42 orders: 5 updated, 1 merged".
What re-parsing does:
Rebuilds each order from its stored messages, using your current templates, bot pins and inbox template lists.
Keeps values that don't come from messages: sale prices you entered, fields you edited by hand, delivery dates, addresses, and package weight and dimensions from carriers.
Merges orders that now share an order number.
Removes orders whose messages now all look like non-order mail, unless you've edited them or entered a sale price.
Skips orders with no stored messages, such as manual orders.
Related
Connect Discord monitor bots: pin a template to a bot.
Embed copier: capture real embeds as samples.
Connect email: limit an inbox to specific templates.
Developer reference: Templates API