Skip to main content

Integration Outbox

The Integration Outbox is Tagnet's durable delivery system for outbound HTTP calls to your ERP, WMS, or any other external system. It backs the HTTP Integration (durable) workflow action: instead of calling your endpoint inline during the workflow run, the action hands the request to the outbox and continues immediately. A background delivery engine takes it from there, retrying automatically and surviving an application restart, so an event doesn't get lost just because your ERP was down for a maintenance window when the tag was scanned.

Choosing between HTTP Request and HTTP Integration​

Tagnet has two workflow actions that call an external endpoint. They are siblings built for different jobs, not two versions of the same thing.

HTTP Request (immediate)HTTP Integration (durable)
When it runsCalls the endpoint now and waits for the replyHands the request to the delivery queue and continues right away
Later actionsCan use the responseCannot see a response. There isn't one yet, and there may not be one for hours.
If the endpoint is downThe action failsThe request is retried automatically for hours before giving up
AuthenticationThe endpoint's connection profile. Actions created before endpoints existed may still carry an inline API key or bearer token.A connection profile only. See Why a connection profile is required.
Best forA call whose response the workflow needs right now, such as a lookup that feeds a later actionPosting an event to a system that shouldn't lose it, such as an ERP or WMS movement notification

If a later action needs to read what the endpoint returned, use HTTP Request (immediate). If the point is simply to make sure the external system eventually hears about the event, and you'd rather Tagnet keep retrying than have the workflow fail, use HTTP Integration (durable).

See Send HTTP Request in the Workflows guide for the immediate action's full behavior.

Setting up an HTTP Integration action​

From a workflow's Actions section, click Add Action and choose HTTP Integration (durable). The configuration is short, because most of it lives on the endpoint:

  • Endpoint: required. Pick one of the integration endpoints defined on your connection profiles. The endpoint supplies the URL, method, headers, body and content type, and its profile supplies the authentication. The action shows the method and full URL of whichever one you pick.
  • Filters: action-level filters narrow which tags from the scan event this action applies to, same as any other action.

The body is rendered once, at the moment the request is queued, and stored with the delivery. A retry hours or days later resends exactly what was rendered at enqueue time, not a re-render against a workflow context that no longer exists. Editing the endpoint afterwards, or rolling it back, affects new deliveries only.

Actions created before endpoints existed carry their own URL, headers and body. They keep working and stay editable, and the dialog offers a one-click Save as endpoint conversion. See Converting an existing action.

Retry count and per-attempt timeout are not configured on the action itself. They come from the Integration / Outbox policy on the Policies tab of the System page, described in How delivery works below, so every durable action in your system shares one consistent retry behavior.

Why a connection profile is required​

Send HTTP Request actions created before endpoints existed could carry an inline API key or bearer token. HTTP Integration never offered that option, and for a specific reason: a queued delivery is stored in the database until it succeeds, possibly for hours. An inline credential would sit in that table in plain text, in a record built to eventually be browsed and inspected. Requiring a connection profile keeps credentials out of the outbox entirely: authentication is resolved fresh from the profile at the moment each attempt is sent, never stored with the request.

This does not mean every endpoint needs credentials. A connection profile's job is to identify the target system, not only to carry authentication. If your endpoint needs no credentials at all, create a profile with Authentication set to None. It is a correct, complete profile, not a placeholder.

For the same reason, custom headers whose name looks like a credential are refused when you try to save the action. That means any name containing auth, token, secret, cookie, credential, or password, plus the qualified key headers: X-Api-Key, Access-Key, Ocp-Apim-Subscription-Key, X-Client-Secret and the like. The check is case-insensitive and ignores punctuation, so api_key and APIKEY are caught too. This catches an Authorization or X-Api-Key header typed in by habit, not just a deliberately smuggled credential. Put it on the connection profile instead, either as the authentication mode's own credential or, if the mode is already carrying a different one, as a secret header.

Headers that merely end in -Key without a credential qualifier are allowed, because they are routing metadata rather than secrets: Idempotency-Key, X-Correlation-Key, and Partition-Key all save normally. If your endpoint requires its own idempotency or correlation header, you can add it here.

What "Queued" means​

When an HTTP Integration action runs, its status is Queued, not Success. This is a deliberate third outcome, distinct from both success and failure:

  • Queued means the request was accepted and durably stored for delivery. The action's job was to hand off the request, and it did.
  • Failed means Tagnet could not even accept the request: the body template failed to render, the connection profile was missing or deleted, or the request body was too large. This is a real failure, and any OnFailure chain reacts to it normally.

Queued says nothing about whether your ERP or WMS actually received the request. The workflow finishes in milliseconds; the delivery may take minutes, hours, or (after enough retries) never succeed at all. This is the tradeoff for durability: Tagnet cannot make the workflow wait for an outcome that might not exist for hours without turning every workflow run into a long-lived process.

To see how the delivery actually went, open the workflow execution's detail page. If you have the Manage Policies permission that the Integration Outbox pages require, the action's status chip and step circle there show the delivery's actual outcome instead of the plain Queued status, once a delivery exists:

OutcomeColorMeaning
DeliveredGreenThe endpoint accepted the request
DeliveringBluePending or in flight, with automatic retries
Delivery failedRedA permanent error; can be requeued once the cause is fixed
Dead-letteredRedRan out of retries; can be requeued
AbandonedAmberAn administrator chose not to resend it

Abandoned reads amber here, even though the Integration Outbox page itself shows it as a neutral status. The two views are answering different questions: the outbox page is telling you a deliberate decision was made and nothing is left to act on, while the execution detail page is telling you the data never reached the destination, which is worth a second look even when abandoning it was the right call.

An action whose request queued a single delivery links straight to it (View delivery). One that queued several shows a count chip per outcome plus a View this run's deliveries link to the filtered outbox list. Either way, the plain Queued status still shows if you don't have the Manage Policies permission, or if the delivery has already been purged by retention.

Run conditions after a durable action​

Because a durable action's outcome is known immediately but its delivery outcome is not, the usual run-condition logic needs a specific read for this action type:

Run conditionWhat actually happens
AlwaysRuns normally, right after the request is queued. Unaffected by any of this.
On SuccessQueued satisfies it. The dependency action's job was to durably accept the request, and it did, so downstream actions run immediately, not once delivery finishes.
On FailureFires only if the request could not be queued, never if delivery later fails.

Important: This is a trap worth knowing about before you build around it. A chain like "post to the ERP, then on failure, notify ops" will not catch the ERP being down. The On Failure condition only ever sees whether Tagnet could accept and store the request, which almost always succeeds; it has no visibility into what happens after that, because delivery happens in the background, independently of the workflow that queued it. Reacting to a real delivery failure (a dead-lettered request, a rejected response) is planned as a future trigger type, not something an On Failure chain can do today.

The workflow editor shows this same warning inline when you set a run condition that depends on an HTTP Integration action.

How delivery works: retries and dead letters​

Once a request is queued, a background delivery engine sends it, independently of the workflow run that created it. Delivery behavior is controlled by the Integration / Outbox policy on the Policies tab of the System page:

SettingWhat it controlsDefault
Max attemptsTotal delivery attempts, including the first, before giving up15
First retry delayWait before the first retry30 seconds
Longest wait between attemptsCap on the backoff curve60 minutes
Per-attempt timeoutHow long a single delivery attempt may take30 seconds
Deliveries sent at onceHow many deliveries the consumer sends concurrently. Applied on restart, unlike the rest of this table1
Largest request bodyRequests over this are rejected at enqueue, not truncated256 KB
Response kept for diagnosisLonger responses are stored truncated32 KB
Idempotency headerHeader name carrying the delivery's unique keyIdempotency-Key

Two other behaviors, per-host concurrency and the circuit breaker that pauses a repeatedly-failing host, are not part of this policy. They are shared with every other outbound call Tagnet makes (Send HTTP Request actions and connection-profile token requests included) and are controlled separately by the Integration / Throttle policy. See Integration / Throttle for its settings.

The default retry budget is deliberately generous, about 8 hours of retrying an unavailable endpoint before giving up, far longer than Tagnet's email retry budget. A short retry window is fine for an SMTP blip; it is useless for an ERP down for a routine overnight maintenance window, which would otherwise dead-letter an entire night's worth of events and leave someone to sort it out by hand.

A response that is clearly not going to succeed on retry, such as an HTTP 400 or 404, fails immediately instead of burning through the retry budget. Only transient-looking failures (timeouts, connection errors, 5xx responses, and a few specific retryable status codes) consume attempts.

If every attempt is exhausted without success, the delivery is dead-lettered. This is distinct from a delivery Tagnet is still working on: a dead letter has stopped retrying and needs administrator attention, but the record is retained (see Retention below), not lost.

Raising "Deliveries sent at once" above the per-host limit only helps when your deliveries target several different systems. Concurrent requests to the same host are capped by the Integration / Throttle policy (5 by default), the same shared limit that already governs Send HTTP Request. Against a single endpoint, extra workers beyond that spend their time waiting for a slot and then hand the delivery back, which delays it without getting anything sent sooner. That handback also uses up one of the delivery's retry attempts, because every attempt is counted whether or not it reached the endpoint. Counting only the attempts that got through would mean a system that is completely unreachable never exhausts its budget and never dead-letters, which is the one situation the budget exists for.

Changing "Deliveries sent at once" takes effect on restart. The worker count is read once when Tagnet starts, so saving a new value leaves the running workers unchanged until Tagnet restarts. Every other setting in the table above applies to the next delivery. When the two disagree, the Diagnostics page says so and shows both numbers.

For the full list of policy settings and how to change them, see Policies.

The idempotency key​

Every delivery attempt, including retries and an administrator's manual requeue days later, sends the same value in the Idempotency-Key header (configurable, see the table above). The key is generated once, when the request is first queued, and never changes for that delivery.

At-least-once delivery means the same request can legitimately reach your endpoint more than once: a response lost to a network blip looks identical, from Tagnet's side, to a request that never arrived at all, so Tagnet has to assume it might not have and try again. Share this header with the team that owns the receiving system so their integration can recognize a resend and avoid double-processing the same event.

Retention​

Delivery records are cleaned up by the Retention / IntegrationOutbox policy, with two independent windows, the same pattern used by Email Delivery:

  • Sent retention: how long to keep successfully delivered rows (default 30 days).
  • Failed / dead-lettered / abandoned retention: how long to keep failed, dead-lettered, and abandoned rows (default 90 days), since these are what you reach for during troubleshooting.

Deliveries in progress (not yet in a final state) are never removed by retention regardless of age.

Delivery counts and timing are kept far longer than the request and response payloads themselves, 365 days by default under the Retention / OperationalRollups policy, so even after a payload ages out, the record that a delivery happened, and roughly when, survives. See Policies for both settings.

Watching deliveries​

The Outbox tab of the Integrations page lists every delivery, newest first, with a status summary across the top. Clicking a status in that summary filters to it, which is usually what you want after seeing a number you did not expect next to Failed.

The search box takes three different things and works out which you pasted: an idempotency key (a 32-character key with no dashes), a workflow execution ID (a dashed ID), or any part of a target URL. Whichever it picked shows as a chip under the box, so you can see how your text was read. The filter panel adds status, target system, endpoint, source workflow, and a queued-date range, plus a Failed or dead-lettered shortcut for the question people actually ask after an outage.

The Endpoint filter is usually the one that matters. A system with four operations tends to fail one operation at a time, not all of them at once. Endpoints are listed for the selected target system, or across all of them when no system is chosen.

The list starts with status, when it was queued, and where it was going. The Target column shows the URL with the connection profile and endpoint under it. The column menu in the table header adds the rest: the workflow action that queued it, the response status code, the last error, when it was delivered, how long the last attempt took, and the idempotency key. Your choices are remembered per user, so a column you turn on stays on next time.

Opening a delivery shows the request exactly as stored (method, URL, headers, body), the response the receiver gave including its status code and the start of its body, the error from the last attempt, and the timing: when it was queued, first attempted, delivered, or when it is next due. The endpoint, workflow, workflow execution, and scan event that produced it are links, so you can go straight from a failed delivery to the exact run that created it, its filters, and the other actions around it. Endpoint and workflow names are stored on the delivery itself, so they still read correctly after a rename or a delete, and each link falls back to plain text when the other side has been purged; executions and deliveries are retained on separate schedules, so either can outlive the other.

Requeuing​

A Failed or dead-lettered delivery can be sent again, either one at a time from its row or its detail page, or all at once with Requeue matching in the Actions menu at the end of the status row, which acts on everything the current filter selects. Up to 5,000 move per run; if more match, run it again.

A requeue resends the stored request as-is. It is never re-rendered against current data, and it keeps its original idempotency key, so a receiver that deduplicates recognises it as the same delivery rather than a new one.

A requeue also works on an Abandoned delivery, one at a time from its row or detail page, if you change your mind about it (see Abandoning a delivery). Requeue matching skips abandoned deliveries, so a bulk requeue after an outage never resends something that was deliberately written off.

Stopping a delivery​

A delivery still waiting to retry can be moved straight to dead-lettered with Stop retrying, for when you already know the endpoint is gone or the payload will never be accepted and you would rather not wait out the remaining attempts. It can be requeued later if that turns out to be wrong.

Abandoning a delivery​

Abandon writes off a Failed or dead-lettered delivery: you know why it failed, and it must not be sent. The usual case is a problem fixed on the receiving side with a data change, which leaves the deliveries queued before the fix incompatible with it. Resending them would only fail again, and leaving them dead-lettered keeps the Dead letters aging alert raised.

Abandon one delivery from its row or its detail page, or everything the current filter selects with Abandon matching in the same status-row menu (up to 5,000 per run, like a bulk requeue). Either way you give a reason, which is shown on the delivery as its last error and recorded with the decision.

An abandoned delivery:

  • Is not resent, and no longer counts as needing attention: it drops out of the Dead letters aging alert and the Requeue matching count. Once a connection has no dead letters left, its Deliveries dead-lettered alert resolves itself. A not accepting deliveries or authentication alert for the connection stays open until a delivery to it succeeds, and the abandon confirmation lists any that are open (see Alerts).
  • Stays in the outbox with the Abandoned status, its request, and the response that made it fail, until the failed-delivery retention window removes it (see Retention).
  • Can still be requeued one at a time if the decision turns out to be wrong.

Which one to use:

SituationAction
The cause is fixed and the delivery should now go throughRequeue
The delivery is still retrying, and you know it will never succeedStop retrying, then decide
It failed, you know why, and it must not be sentAbandon

Requeuing, stopping, and abandoning are all recorded in Security Events, naming who did it and which system was affected. Simply viewing deliveries is not recorded.

Analytics​

The Analytics tab of the Integrations page shows a trend view over 1 hour, 6 hours, 24 hours, or 7 days, for all target systems or one at a time.

The four figures across the top are deliveries completed, failure rate, average endpoint response time, and average queue wait. Below them:

  • Delivery volume splits each 15 minutes into sent, failed, and dead-lettered.
  • Endpoint response time plots the average alongside the slowest single attempt, which is what you want when chasing an intermittent timeout rather than a general slowdown.
  • Queue wait is how long deliveries sat before Tagnet first tried them. This is the number that moves first when an endpoint slows down enough that deliveries arrive faster than they can be sent, well before anything actually fails.
  • Attempts per success shows retry pressure. A value of 1.0 means everything succeeded first try; a value drifting upward means an endpoint is turning flaky long before the failure counts react.
  • Data sent is the total request body volume.

Two things to know about how this data is built. It is aggregated into 15-minute buckets when a delivery reaches a final state, so the charts can trail live activity by up to 15 minutes, and a delivery still retrying does not appear until it finishes. And response time only counts attempts that actually reached the endpoint: a delivery rejected before the request went out (an unreachable host, a token failure) counts as a delivery but contributes no timing, so a run of those does not make the endpoint look instant.

Because these counts are kept for 365 days while the deliveries themselves are purged at 30, this page still answers "was this endpoint healthy last quarter" long after the individual requests are gone.

Diagnostics​

Analytics tells you what happened. Diagnostics, the next tab, tells you what the delivery engine is doing right now, which is where to look when deliveries are going out slowly and you want to know why.

  • Waiting in queue is how many deliveries have been handed to a worker but not picked up yet. Anything other than zero for a sustained period means deliveries are arriving faster than they can be sent.
  • Workers busy shows how many are mid-delivery against how many are running. If this sits at full, the queue is the bottleneck and raising Deliveries sent at once may help, but only if your deliveries go to more than one system (see the note the page shows you).
  • Endpoint health is one card per external system, with the most important thing on it being the circuit state. Healthy means requests are going out normally. Rejecting means Tagnet has stopped sending to that host after repeated failures and is waiting before trying again, and every rejected request still uses one of the delivery's retry attempts. Probing means it is testing with a single request to see whether the host has recovered.
  • Settings in force shows the retry and size limits actually being applied, including how long an outage the current settings can ride out before a delivery is dead-lettered.

The page refreshes every five seconds while Live is on, and the queue depth chart builds up while you have the page open; until its second sample the section shows a Sampling note in its place. Everything on this page is live server state: the counters start again from zero when the Tagnet service restarts, and the permanent record of what was delivered stays in the outbox and its analytics.

Endpoint health is shared with the immediate Send HTTP Request action, so a host used by either kind of action appears here. The Workflows Diagnostics tab links back to this page for it.

Current limitations​

  • One request per scan event. A durable action sends a single request per triggering event; per-tag fan-out (one request per tag) and non-JSON body formats such as XML are not yet supported.

Where to go next​

  • Set up authentication with the Connection Profiles guide.
  • Define the operations you send to, and test them before a workflow depends on them, with the Integration Endpoints guide.
  • See the full action catalog, conditions, and run conditions in the Workflows guide.
  • Tune retry behavior and retention windows in the Policies reference.