Skip to main content

Run Delivery Controls

Skip or re-point a Spec's Dispatch nodes for one POST /v1/run request with dispatch and bindings, read warnings and dispatch_skipped, and handle late failures.

A Spec's Dispatch nodes deliver every run's payloads to the destinations their bindings name. Two optional fields on POST /v1/run change that for one request without touching the Spec or its bindings. dispatch=false skips every Dispatch node for the request, so nothing is delivered for its documents. bindings is a JSON object keyed by Dispatch node id: a destination id re-points every binding of that node to that destination for this request, and null skips that node. Each re-pointed binding keeps its own field map, serializer, and retry policy; only the target changes.

The node ids are the ones shown in the Spec editor and in the signal_filter.match.stage_id of your existing dispatch.* bindings. dispatch=false is shorthand for "every node maps to null", so combining it with a non-null override is rejected. The map holds at most 64 entries and every value must be a destination UUID or null. Skipped nodes are not silent: each one records a dispatch with status skipped on the pipeline, visible through GET /v1/pipelines/{id}/dispatches, so the run's history shows that delivery was deliberately withheld.

Skip all delivery, or re-point one node and skip another

# Skip every Dispatch node for this request
curl -X POST https://api.talonic.com/v1/run \
  -H "Authorization: Bearer $TALONIC_API_KEY" \
  -F spec_id=SPEC_ID \
  -F dispatch=false \
  -F files=@invoice.pdf

# Re-point node A to a test destination, skip node B
curl -X POST https://api.talonic.com/v1/run \
  -H "Authorization: Bearer $TALONIC_API_KEY" \
  -F spec_id=SPEC_ID \
  -F 'bindings={"NODE_A_ID":"TEST_DESTINATION_ID","NODE_B_ID":null}' \
  -F files=@invoice.pdf

What is checked at submit time

The request is refused with 400 invalid_delivery_controls when a key is neither a Dispatch node of the Spec's published version nor of the newest pipeline's frozen rail, when a value is not an active destination in your workspace, or when a value's connector cannot carry one of the node's bindings, for example a Google Sheets destination for a JSON binding, or a legacy-signature webhook binding pointed at object storage. Nothing is ingested when the controls are invalid, so fix the map and resubmit.

Some situations are accepted with a warning in the 202 response instead. Re-pointing a node that has no active binding gets no_binding_for_node, because nothing will be delivered for it regardless of the override. The early trigger modes read the Spec's published version while on_run_completed reads the rail frozen when the pipeline was created, and an append request reuses the newest pipeline; after you add or delete a Dispatch node and republish, the two can disagree for a while. A key that exists on only one side is accepted with node_not_in_live_pipeline or node_not_on_published_version, naming the pipeline concerned, so you can send both ids when you need both covered.

202 response with a warning

{
  "run_id": "a8716d18-978d-4d19-8ca5-8b3784ca857c",
  "spec_id": "1fc7807e-e1aa-4504-b796-5709986e78ed",
  "status": "processing",
  "input_count": 1,
  "poll_url": "/v1/run/a8716d18-978d-4d19-8ca5-8b3784ca857c",
  "documents": [ { "document_id": "c3d4e5f6-a7b8-9012-cdef-123456789012", "filename": "invoice.pdf", "size_bytes": 184320, "source": "file", "deduplicated": false } ],
  "warnings": [
    { "code": "no_binding_for_node", "message": "Dispatch node 'NODE_A_ID' has no active binding — nothing will be delivered for it regardless of the override." }
  ]
}

GET /v1/run/{id} echoes the controls whenever a request sent them: dispatch: false (only when set), the bindings map, and dispatch_skipped, which is true when the controls suppress at least one Dispatch node. Use dispatch_skipped in dashboards to tell "nothing arrived because the caller opted out" apart from "nothing arrived because delivery failed".

What happens later

  • Bindings and destinations can change between submit and delivery. If an override destination has been deleted or deactivated by the time the payload is sent, that delivery fails with destination_override_missing and lands in the dead-letter queue. It never falls back to the binding's own destination.
  • A skipped dispatch cannot be re-dispatched: POST /v1/pipelines/{id}/dispatches/{dispatchId}/redispatch answers 409 DISPATCH_SKIPPED_BY_REQUEST. To deliver it after all, trigger the node manually with POST /v1/pipelines/{id}/dispatches/{stageId}; manual triggers ignore request controls.
  • A re-dispatch of a dispatch that did ship inherits its frozen selection, including any per-request destination override.
  • Controls attach to a document's first request on a pipeline. Re-submitting the same document into an append pipeline with different controls does not change what later re-emissions (a revised matcher verdict, a new App verdict) do for that document.
  • Under append, a pipeline-level payload such as an assembly or data-product dispatch aggregates several requests. Records of a skipping request are left out and the rest ships; a destination override applies only when every contributing request names the same destination.
  • The legacy document.structured and run.completed deliveries are not governed by these fields.
An override is a hard redirect, not a preference. When the override destination is gone at send time the attempt fails with destination_override_missing and goes to the DLQ instead of silently reaching the production destination. Recreate or reactivate the destination, then replay the DLQ entry.

Frequently asked questions

How do I run a Spec without delivering anything?+
Submit POST /v1/run with dispatch=false. Every Dispatch node records a skipped dispatch for the request and nothing is delivered for its documents. GET /v1/run/{id} then reports dispatch: false and dispatch_skipped: true.
How do I send one request's results to a test destination?+
Pass bindings with the Dispatch node id as key and the test destination id as value. Every binding of that node delivers to the test destination for this request only, keeping its own serializer, field map, and retry policy. The Spec and other requests are unaffected.
What happens if the override destination is deleted before delivery?+
The delivery fails with destination_override_missing and goes to the dead-letter queue. It never falls back to the binding's own destination, so a test request cannot leak into production by accident.
Why did re-dispatch return 409 DISPATCH_SKIPPED_BY_REQUEST?+
The dispatch was skipped because the request asked for it, and a skipped dispatch is terminal. Trigger the node manually with POST /v1/pipelines/{id}/dispatches/{stageId} if you now want it delivered; manual triggers ignore request controls.
Do delivery controls affect the run.completed webhook?+
No. The legacy document.structured and run.completed deliveries are not governed by dispatch or bindings. The controls apply only to the Spec's Dispatch nodes.