Bindings
A delivery binding is the routing rule that connects platform events to a destination: it joins a signal filter (which events?) to a deliverable type (what payload shape?) to a destination (ship where?) via a serializer (encoded how?). On create, the backend validates all four pieces form a compatible triangle — the serializer must support the resolver's shape, and the connector must support the serializer format. This six-predicate validation ensures you never end up with a misconfigured binding that cannot deliver.
Optional field_map (drop, rename, and static rules) lets you reshape the payload without custom code. Rename rules are rules entries with a source and target field name, drop lists fields to exclude, and static injects literal key/value pairs. The three operations compose in a fixed order: drop first, then rename, then static injection (static values are added last and win collisions). Optional delivery_policy overrides the default retry ladder (7 attempts over ~10 hours with exponential backoff: 0s, 30s, 2min, 8min, 30min, 2h, 8h) and maximum attempts.
The compatibility triangle is enforced on every create and update via six predicates. The backend checks that: (1) the signal_filter is well-formed with a known event type and valid match values, (2) the deliverable_type resolves to a registered resolver, (3) the serializer_format resolves to a registered serializer, (4) the serializer supports the resolver's output shape, (5) the connector's supported serializer list includes the chosen format, and (6) the resolver's compatible event types include the signal filter's event type. If any predicate fails, the binding is rejected with a descriptive error — you never end up with a binding that cannot deliver.
Use field_map to tailor the payload for each downstream consumer. Rename rules (rules: [{ "source": ..., "target": ... }]) map internal field names to the receiver's expected names. Drop rules exclude fields the receiver does not need. Static rules inject constant values (e.g., a source: "talonic" tag) into every payload. These three operations compose in order: drop first, then rename, then static injection.
For best results, create one binding per downstream consumer per event type. This gives you independent control over payload shape, retry policy, and serialization format for each integration point. Most teams start with a document.extracted binding to a webhook and expand to run-completion and reviewer-action events as their integration matures.
curl -X POST https://api.talonic.com/v1/delivery/bindings \
-H "Authorization: Bearer $TALONIC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Approved records to S3 as CSV",
"signal_filter": { "event_type": "result.approved" },
"deliverable_type": "record.approved",
"destination_id": "dest_s3",
"serializer_format": "csv_file",
"field_map": {
"drop": ["internal_notes", "debug_trace"],
"rules": [
{ "source": "invoice_number", "target": "inv_no" },
{ "source": "total_amount", "target": "amount" }
],
"static": { "source": "talonic", "pipeline": "production" }
},
"delivery_policy": {
"max_attempts": 5,
"backoff_schedule": [0, 10000, 60000, 300000, 1800000]
}
}'Withholding fields per destination: excluded_fields
A binding for the pipeline.capture deliverable can carry `excluded_fields`: a list of field names to omit from the delivered payload. This is a per-destination egress control — the fields stay in the data product, the grid, and every other binding; only this destination stops receiving them. The list holds up to 200 entries of 1-256 characters each, and matching is exact and case-sensitive against the schema field_name and the cell field_key. Declaring excluded_fields on any other deliverable type is rejected at write with a 400, because it would be stored but never applied — a silent no-op is the wrong failure mode for a control whose job is keeping data in.
include: false and a schema field's suppress_output hide fields from data products and published read contracts — they do NOT remove a populated value from the delivered capture payload. If a field must not reach a destination, exclude it on that destination's binding.curl -X POST https://api.talonic.com/v1/delivery/bindings \
-H "Authorization: Bearer $TALONIC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Capture to partner webhook (no margins)",
"signal_filter": { "event_type": "document.extracted" },
"deliverable_type": "pipeline.capture",
"destination_id": "dest_001",
"serializer_format": "json",
"excluded_fields": ["internal_margin", "buy_rate"]
}'
# Matching is exact and case-sensitive against field_name / field_key.
# Up to 200 entries, each 1-256 characters. Only the pipeline.capture
# deliverable accepts excluded_fields; other types are rejected (400).There is a trap to plan around: an exclusion key that matches no field is accepted silently at write time and withholds nothing — the payload delivers unchanged, with only a server-side warning at delivery time. A typo or a renamed schema field therefore fails open, not closed. The catch is the binding preview: previewing a binding that carries exclusions returns an exclusion_check block with checked, unmatched_keys[], and an optional reason. unmatched_keys names every exclusion entry that matched nothing, and checked: false means the preview fell back to a structural sample and could not verify the keys at all — it is explicitly not a claim that they match. Preview after every exclusion change, and treat any unmatched key as a bug.
POST /v1/delivery/bindings/:id/preview endpoint is currently a stub and does not yet return the real preview shape — verify exclusions from the binding editor.The field_map feature eliminates the need for middleware transformation layers between Talonic and your downstream systems. The three operations — drop, rename, and static injection — compose in a fixed order: excluded fields are removed first, then remaining fields are renamed to match your downstream schema, then static values are injected. This means you can reshape the payload to match exactly what your ERP, data warehouse, or analytics system expects without writing any code or deploying a transformation service. Most teams create one binding per downstream consumer per event type for independent control over payload shape.