Destinations
Settings → Integrations → Destinations (Planning). A destination is one
place committed decisions go: a spreadsheet your team works in, your system’s
own API, or a URL your own system listens on. Each one decides which decisions
it receives, what its columns are called, and when it runs.
Destinations are the one integration that writes: a purchase order to raise,
a price to change, stock to move — and then reads back what happened to it.
Every workspace has them. Only owners and admins can add, change or remove one.
What is delivered
Every line of a committed decision — one product, one action — becomes one row
or one record. A line carries who decided and when, the project and buyer scope;
the product (SKU, supplier SKU, supplier, name, category, your system’s
identifiers and links); and the decision (quantity or price, the recommendation,
unit cost, margin before and after, required-by date, rationale).
A line is delivered once. Committed again unchanged, it is skipped; changed, its
row is updated in place.
Deliver decisions to a spreadsheet
Add a destination → Google Sheet.
- Pick the spreadsheet. The step lists every spreadsheet someone in your
workspace has already shared with Twelfth — owned or shared by a member, or
by an address on your company’s domain — newest share first, each marked
Editor or Viewer. Pick one. - Not listed? Open the spreadsheet, click Share, and add the Twelfth
address shown under the list (Copy address copies it) as Editor.
Come back to the tab and it appears. Or paste the link: a pasted link is
checked at once. Twelfth shows the title, who shared it and whether the
share is Editor; a Viewer share is refused and the step shows the address
again with Check again. - Choose where rows land:
- Tabs Twelfth creates — one tab, a tab per supplier, per buyer scope or
per decision kind. Every tab Twelfth makes ends with Tab name ends
with (Twelfthby default, so a supplier’s tab reads
Mattel - Twelfth), is coloured plum and is added after your last tab.
Rename a tab if you like: Twelfth remembers what each tab is for and
keeps writing to it under your name. Twelfth writes only to tabs it
created and stamps each one; your own tabs are never touched. Delete a stamped tab and
Deliver now brings its rows back on a fresh one. - A tab you already use — pick one of the spreadsheet’s tabs. Twelfth
finds its header row (row 10 in the Gamesmen Retail Express order and
product templates, row 1 in the transfer template), then reads samples
and proposes what each header
reads as, and shows the table: their header (with sample values), reads
as, filled by. A warning sits inline on a header it concerns — a column
that holds mixed values, a header that repeats. Change any row; the
Columns step shows the same table again without a preset chooser. Twelfth
writes into that tab’s columns and adds a Twelfth line ID column if the
tab has none. Instructions, outlet and supplier cells, and type notes
above the header stay as they are. Check outlet and supplier in the
spreadsheet before uploading a purchase order to Retail Express.
- Tabs Twelfth creates — one tab, a tab per supplier, per buyer scope or
Each linked tab holds up to 5,000 decision rows and 80 columns. The Product
Master template has 53 columns; the added Twelfth line ID is the 54th. A full
catch-up reads at most 5,000 ledger lines. For a manual Retail Express upload,
copy only the template’s import columns into the upload file: A:G for order
details, A:BA for Product Master, or A:D for the four-column transfer sheet.
The extra Twelfth line ID column stays in Google Sheets so later syncs update
the same row.
The columns you fill in
Every preset ends with four columns that are yours: Reference, Raised at,
Status and Notes. Twelfth reads them back nightly and never
overwrites them. A filled-in Reference marks the line acknowledged; a
filled-in Raised at marks it executed.
Your system’s API
Add a destination → Your system’s API. Twelfth itself calls your system’s
endpoint with your credential when a decision lands — Retail Express (hosted,
self-hosted or through a bridge your IT runs), or any other system — and records
the reference it returns. If the kind is greyed out with Not configured in this
environment, this environment cannot hold credentials yet; ask Twelfth.
- Preset. Where Twelfth already reads the workspace’s Retail Express,
Retail Express fills the system name, the purchase-order path and the
API-key header; Custom starts blank. Elsewhere there is no preset to
choose: every system starts blank. - System and Base URL — the name shown on the card and everywhere else
(Retail Express,Cin7,Our order bridge), and the endpoint the paths
are added to, for examplehttps://integrations.example.com.au/retail-express. - Paths, one per kind:
/purchase-orders,/prices,/transfers. At
least one is required; a kind with no path is not sent here. - Auth: None, API key (header name, default
x-api-key), Bearer, or
Basic (user:password). The credential is stored encrypted and never shown
again. When editing, leave it blank to keep the stored one. - Requests: Per decision (a purchase order with its lines) or Per line.
Body: Twelfth envelope (below) or Mapped fields only — exactly the
columns you mapped, one object per line, as{ "lines": [...] }when
grouped per decision. Reference path: where the reference sits in the
reply, as a dot path —id,purchaseOrder.id. A map keyed by Twelfth line
ID at that path also works.
Check and test order
- Check calls the base URL with the credential and answers in one line:
Reachable · credential accepted · 210 ms, or what went wrong. A401or
403reads credential refused. - Send a test order POSTs a sample request to the kind’s path with
X-Twelfth-Dry-Run: trueand shows the reply compactly, with every path in
it that could be a reference as a chip. Click a chip to set the reference
path; the one Twelfth suggests is marked. Nothing is raised: your endpoint
should treat a dry-run request as a validation and reply as it would for the
real thing.
Neither button saves anything.
What Twelfth sends (Retail Express example)
One JSON purchase order per decision (or per line), to the path for its kind,
with the Twelfth envelope body:
{
"twelfthDecisionId": "…",
"kind": "purchase_order",
"supplier": "Mattel",
"supplierKey": "mattel",
"sourceSupplierId": "1842",
"buyerScope": "Toys",
"decidedBy": "sam@example.com",
"decidedAt": "2026-09-28T04:10:00.000Z",
"rationale": "…",
"links": { "decision": "https://…", "project": "https://…" },
"lines": [
{
"lineId": "…",
"decisionId": "…",
"kind": "purchase_order",
"fields": { "ProductId": "10234", "ManufacturerSKU": "ABC-123", "Qty": 24, "…": "…" },
"sourceProductId": "10234",
"sku": "ABC-123",
"supplierSku": "MAT-ABC-123",
"productName": "…",
"quantity": 24,
"unitCostEx": 12.5,
"price": null,
"requiredBy": "2026-10-14",
"lane": null,
"line": { "twelfth": { "…": "…" }, "source": { "…": "…" }, "decision": { "…": "…" } }
}
]
}
fields is the line in the columns you mapped (the Retail Express purchase
orders preset gives the bulk-upload names); line is the whole line. Every
request carries an Idempotency-Key, so a retry never raises the same order
twice.
A 2xx reply with a reference at the reference path marks every line in the
request acknowledged, with that reference as its purchase order number. A
2xx without one is delivered; the lines wait for a reference. A 401 or
403 loses the connection: nothing further is attempted and the card says
Retail Express refused the credential. Update the API key or token. Edit the
destination and enter the new one; delivery resumes on the next trigger or with
Deliver now. Any other non-2xx is a failed attempt, retried on the
schedule below.
Webhook
Add a destination → Webhook, with a URL and, for signed requests, a shared
secret (at least 8 characters).
Twelfth POSTs each batch of decisions as JSON:
{
"destination": { "id": "…", "name": "Supplier orders" },
"sentAt": "2026-09-28T04:10:00.000Z",
"lines": [
{
"lineId": "…",
"decisionId": "…",
"kind": "purchase_order",
"fields": { "SKU": "ABC-123", "Qty": 24, "…": "…" },
"line": { "twelfth": { "…": "…" }, "source": { "…": "…" }, "decision": { "…": "…" } }
}
]
}
Every request carries an Idempotency-Key, X-Twelfth-Destination and
X-Twelfth-Timestamp (Unix seconds). With a secret set, it also carries
X-Twelfth-Signature: sha256=HMAC_SHA256(secret, "<timestamp>.<body>")
over the raw body. Reply 200 to acknowledge; to hand back your own reference
per line, include { "references": { "<lineId>": "PO-48812" } }. A line with a
reference is acknowledged. Anything other than a 2xx is a failed attempt and
is retried.
Filters
Each destination receives only the lines its filter admits; the card shows the
filter as one sentence.
- Which decisions: orders, price changes, stock transfers — any mix; nothing
chosen means every kind. - Buyer scopes and suppliers, from the workspace’s own lists.
- Raised projects only: wait until the project is raised. On by default when
a destination receives orders and nothing else. - Under More: Only the last (days) and Leave out SKUs starting with
(comma-separated prefixes).
A line that stops matching every destination’s filter is withdrawn on the
ledger. Nothing is removed from the destination.
Mapping presets
The mapping decides which fields go, in which order, under which names. Start
from a preset and change anything. The Retail Express presets are offered only
where Twelfth already reads the workspace’s Retail Express; everywhere else the
mapping starts from Twelfth columns and there is no preset to choose.
| Preset | What it is for |
|---|---|
| Twelfth columns | Every identifier, the decision, and the four columns you fill in. The default. |
| Retail Express purchase orders | The MassUploadPurchaseOrders headers first — ProductId, ManufacturerSKU, SupplierSKU, SupplierSKU2, Qty, SupplierBuy — then the canonical columns. |
| Retail Express products | The MassUploadProducts price headers first — ProductId, POSPrice, WebPrice, DiscountPrice, DiscountEnd, SupplierBuy, BuyPriceEx, RRP — one price decision setting POS and web alike, then the canonical columns. |
Each row names the column, what it reads as (a field of the line, a fixed
value, or a template such as {{source.sku}} — {{decision.quantity}}) and who
fills it in. Columns you fill are read back and never overwritten. The
Twelfth line ID column cannot be removed — it is how a changed line finds
its own row.
Preview shows how many lines the filter matches, how they fall across tabs,
and the first rows in the destination’s shape, before anything is delivered.
When to send
Tick any of three, under Name and filter:
- As each decision is made — a line lands the moment a buyer commits it.
Pick it for a sheet your team works from during the day. - When a project is raised — the whole project lands at once, after
sign-off. Pick it for a system that places orders. An orders-only destination
with raised projects only first sees its lines here. - Nightly catch-up at 05:00 (workspace time) — anything changed or missed
is sent again, and the columns your team filled in are read back. Leave it
on: it is what fills in Reference and Raised at. A destination linked
today has its first catch-up tomorrow.
Link and deliver links the destination at once and sends the first
delivery in the background; the dialog follows it and links straight to the
sheet. Deliver now runs the whole filter at once. The On / Off switch
keeps everything and delivers nothing while off.
Retries and health
A failed delivery is retried at 1, 5, 15, 60 and 240 minutes, five attempts in
all. After that it is dead and the card offers Retry all (and a per-row
Retry under Recent deliveries).
| Health | Meaning |
|---|---|
| Healthy | The last delivery landed. |
| Degraded | Some lines did not land on the last run. |
| Failing | Three or more runs in a row have failed. |
| Connection lost | Twelfth can no longer open the spreadsheet, your system refused the credential, or the endpoint refused the request. The card says which to fix. |
| Off | Switched off. |
Remove unlinks a destination. Nothing on your side is deleted.
What the ledger shows
- Recorded — committed in Twelfth; nothing has left yet.
- Staged — delivered to at least one destination, not yet seen in your
system of record. - Executed — seen in the system of record: a Raised at date on the sheet,
or a raised date reported by your system. A reference alone is acknowledged,
one step short. - Withdrawn — the line no longer matches any destination’s filter.
The decision’s page carries a Delivered to block naming each destination,
the status there, a link to the row where one exists, the reference that came
back, and any error. The exported CSV carries a State column.
Who is notified
- Workspace owners and admins (and any extra address on the destination)
hear when a destination goes failing or loses its connection, when a
delivery gives up, and when a nightly read-back finds a deleted row — by
email, and in the workspace’s chat channel where one is connected. At most
one message per destination per day. The daily brief carries one line. - The buyer who decided sees a line that gave up, or was executed, on the
ledger entry and on the project’s Raised stage. No email.
Nobody hears about an individual attempt, a retry, or a run that succeeded.