跳至主要内容

Storefronts and marketplaces

Post each order to the books exactly once

An order is paid on the storefront, and some minutes later an invoice should appear in the ledger. The difficulty is not the posting. It is that the same order can arrive twice: Shopify retries a webhook it believes failed, and a run that crashed halfway does not know whether the invoice landed. A second invoice is not a display bug — it overstates revenue, and running the step again does not take it back. This is the point where a workflow tool stops being enough.

Triggers
Two
Runs
Every 15 minutes
Stack
5 tools
Durable execution
Required

The flow

The top track records the sale in a table you own, and writes nothing to the ledger. The bottom track posts on a timer, and refuses to post an order it has already claimed.

Platform

An order is paid

Shopify Admin API

Orchestration

Build the journal line

n8n · Make

Data

Write the posting key

Sheets · Airtable

Orchestration

Every 15 minutes

n8n schedule

Orchestration

List what is unposted

n8n

Orchestration

Missing from the ledger?

Temporal · Inngest

Platform

Post the invoice

Xero API

Orchestration

Leave it alone

Step by step

  1. 01

    An order is paid

    Shopify Admin API

    A webhook fires on payment. Treat it as a signal that an order exists, not as permission to post — the same delivery can arrive again, and Shopify says so in its own documentation.

  2. 02

    Build the journal line

    n8n · Make

    Turn the order into the fields your ledger expects: net, tax, platform fee, payout account. Nothing is written here. The step is pure computation, so re-running it costs nothing — which is exactly why it belongs in the workflow tool.

  3. 03

    Write the posting key

    Sheets · Airtable

    One row per order, keyed on the order id, with a posting state. This row — not the webhook — decides whether an order still needs posting. Claim before you write, confirm after.

  4. 04

    Every 15 minutes

    n8n schedule

    Runs regardless of any webhook. A delivery that never arrived leaves nothing to notice, and month-end is a poor time to discover it.

  5. 05

    List what is unposted

    n8n

    Read rows that were claimed but never confirmed as posted. That set includes runs which died between the ledger write and the confirmation — the case a workflow tool loses quietly.

  6. 06

    Missing from the ledger?

    Temporal · Inngest

    Look the order id up in the ledger before writing, and hold the lookup and the write inside one run that can be retried whole. This is the step n8n and Make cannot own: neither records that the write already succeeded, so a retry after a lost response re-posts the invoice and books the revenue twice. Either durable execution, or an idempotency key the ledger itself enforces.

  7. 07

    Post the invoice

    Xero API

    Write the invoice with the order id in the invoice reference, and send the same stable order key in Xero's Idempotency-Key header. The reference is for lookup and reconciliation; the header is the part Xero treats as the retry guard. If another ledger does not enforce one, the reference plus the check above has to live inside the same durable run.

What the platform will not allow

None of the caution above is taste. Each part answers a behaviour the platforms document themselves.

  • Webhook delivery "isn't always guaranteed", and Shopify "doesn't guarantee ordering within a topic, or across different topics for the same resource". The same page tells you to ignore duplicate deliveries using the X-Shopify-Webhook-Id header — a header that exists because the same order event does arrive more than once.

    Shopify — About webhooks (best practices)
  • Shopify allows one second to connect and five seconds for the whole request, then retries eight times over four hours; after eight consecutive failures an Admin API subscription is deleted automatically. The documentation's own advice is to queue and respond first — so a ledger write held inside the webhook handler will time out, and the timeout buys you a second delivery of the same order.

    Shopify — Deliver webhooks through HTTPS
  • Xero documents client-supplied idempotency for mutating POST, PUT and PATCH requests through the Idempotency-Key HTTP header. The key is per app, capped at 128 characters, and the cached response is for the same exact request for six minutes.

    Xero API — Idempotent requests
  • The Xero invoice model exposes a Reference field, so the storefront order id can be written onto the invoice for lookup and reconciliation; that field is not the idempotency key itself.

    Xero Accounting API — Invoices
  • What "the receiving system enforces it" looks like, in a system that documents it: Stripe saves the status code and body of the first request for a given key, and subsequent requests with the same key "return the same result, including 500 errors". Keys run to 255 characters, may be pruned once "at least 24 hours old", and reusing one with different parameters is an error rather than a second write. If your ledger has no equivalent, the guard falls back to your own key table inside a durable run.

    Stripe API reference — Idempotent requests
  • The GraphQL Admin API is metered by calculated query cost rather than request count: 100 points per second on standard plans, and no single query may exceed 1,000 points. A month-end catch-up that re-reads a large order set is paced by that budget, not by how fast the workflow loops.

    Shopify — API rate limits

When this is not worth building

Three cases where the upkeep costs more than the double posts.

  • You post one daily total by hand and your accountant is content with it. A summarised journal entry is a single line a day; automating per order buys precision nobody asked for, and introduces a system that can double-post.

  • Your ledger has no external reference field to key on. With nowhere to record the order id on the invoice, the check in this flow has nothing to look up, and you are trusting your own table to be right on its own.

  • Nobody reconciles. If no one compares the ledger against the payout report at month end, a double post survives, and the automation has only made the wrong figure arrive sooner.

Related reading

联络我们

这些流程,你真正应该做哪一条?

我们每星期都在为香港的运营团队跑这些流程。告诉我们哪个环节正在耗你的时间,我们会告诉你自动化划不划得来。

开始对谈