nod.

CAPI delivery, health, and retries

What happens when a send to Meta fails, how retries and backoff work, and how to read the health badge.

Updated July 31, 2026

Every Shopify order that qualifies for CAPI triggers a server-side "Purchase" send to Meta. Most sends succeed on the first try. This article explains what nod. does when one doesn't, so you know when to act and when to leave it alone.

The send path

When an order comes in, nod. tries the send once. If that attempt fails with a network error, a timeout, or a 5xx from Meta, it retries once more after a short delay. A 4xx response (a permanent rejection, like a bad token) is not retried inline — retrying it wouldn't change the outcome.

If both the first attempt and the inline retry fail, nod. doesn't drop the event. It writes the event to a durable queue so the conversion isn't lost. A cron job checks that queue every 15 minutes and works through the oldest pending rows first.

Retry cadence and backoff

Rows in the queue follow a backoff ladder — each failure pushes the next attempt further out, so a temporary Meta outage doesn't turn into a hammering loop:

AttemptWait before this attempt
15 minutes
230 minutes
32 hours
46 hours
5(final attempt)

After 5 failed attempts, the row is marked dead. Nothing brings a dead row back automatically — the conversion is permanently given up on. In practice this only happens when something stays broken for hours (an expired token nobody reconnected, a dataset that was deleted, and so on), not from a single blip.

What pauses sends without burning an attempt

Some situations aren't really "failures" — they're just not send-able yet. If a queued row's workspace is unconfigured, the master switch is off, or the Meta token is expired at retry time, nod. skips that row without counting it as a failed attempt. It pushes the row's next try out by about an hour and moves on, so one stuck workspace doesn't crowd out everyone else's retries. As soon as the underlying issue is fixed, the row picks back up with all its attempts still available.

Token expiration

If your Meta access token expires, sends don't fail loudly — they pause. Live orders stop generating new sends, and any rows already sitting in the retry queue wait rather than burn attempts against a token that would just get rejected again. Nothing is lost during this window.

Reconnecting Meta resumes everything: new orders start sending again immediately, and queued rows pick up on the next cron pass (within about an hour at most) using the fresh token. You don't need to do anything beyond reconnecting — no manual retry, no re-sending old orders.

Reading delivery and readiness separately

The status badge answers one narrow question: can nod. currently deliver an eligible server event? It is not proof of consent coverage, Meta browser/server dedup, or Meta match quality.

BadgeMeaningAction
HealthyEnabled, with no current delivery error or recorded skipCheck readiness before treating the setup as complete
PausedThe master switch is offTurn it back on if you want sends to resume
Meta token expired — reconnectToken has expired; sends are pausedReconnect Meta
Last send failed (status <code>)The most recent send got an HTTP error from MetaUsually resolves on its own via retry; investigate if it persists
Last send failed (network error)The most recent send timed out or hit a network errorUsually resolves on its own via retry
Last eligible order was skippedAn order reached the gate but was not allowed or ready to sendRead the 28-day skip breakdown and fix the named reason

A failed-send badge clears itself back to Healthy the moment any later send succeeds — including a successful retry from the queue. You don't need to clear it manually.

Below the badge, nod. shows identifier-free 28-day readiness aggregates:

  • Order key coverage: share of seen orders with the stable Shopify order key.
  • Event time accuracy: share using Shopify's original order creation time.
  • Event id coverage: share carrying the stable per-order CAPI event id.
  • Delivery: sent, failed, and skipped totals.
  • Consent: granted, unknown, and denied totals, plus the skip reasons. Unknown and denied consent do not send.
  • Meta match rate: shown only when a provider feed supplies it. "Not available" is not treated as zero and not reported as healthy.

Browser/server dedup has its own status. A delivered CAPI event does not prove that Meta observed a browser event with the same event id. nod. therefore shows Dedup not verifiable until matching provider evidence exists.

What needs no action

  • A single failed send that later succeeds via retry. This is the queue doing its job.
  • A "skipped" retry while a token is expired. It resumes on reconnect.
  • The normal 15-minute cadence of the retry cron. Queued rows don't all clear instantly — give it a few cycles.

When to act

  • The badge reads Meta token expired — reconnect. Reconnect Meta on the Tracking page.
  • The badge reads Last send failed and hasn't cleared after a day or more. That suggests something is wrong beyond a transient blip — check your dataset id is still correct and that the connected Meta account still has access to it.
  • You suspect a conversion was permanently lost. A row only reaches dead status after 5 attempts spread over several hours, so this points to a problem (bad dataset id, revoked access) that was live the whole time. Fix the underlying issue so future orders send correctly — dead rows themselves are not recoverable.