Attribution Data API

Get cost per declared outcome

Returns the true cost per unit of value: for every outcome your spans declare (see the tracing guide), completed, failed, and unresolved units side by side. Call it with a GET request to /attribution-data/by-outcome, authenticated with a restricted API key and the "costs:read" scope.

Returns the true cost per unit of value: for every outcome your spans declare (see the tracing guide), completed, failed, and unresolved units side by side. Use this to price against real unit economics; the cost of runs that failed stays visible as its own line instead of inflating the completed average. A unit is one execution of an outcome-declaring span. Its cost is the full cost of that span's call subtree, plus the session's untraced events when the outcome span is the session's only root span. Retried units (same unit_key across attempts) count once while their cost sums across attempts; retried_unit_count reports how many units needed more than one attempt. The date range filters on when a unit RESOLVED (its completion or failure event), or on last activity for unresolved units, so a unit's cost may predate the range. Units that declared an outcome, never resolved, and have been inactive longer than unresolved_after_hours are reported as unresolved; terminal-less units younger than that threshold are treated as still running and excluded. Requests count toward your per-API-key rate limit; sustained overruns return 429 with the standard error envelope.

Authentication and scopes

Authenticate with a restricted API key in the Authorization: Bearer <key> header. This endpoint requires the costs:read scope.

Parameters

NameInTypeRequiredDescription
start_datequerystringYesStart of date range (ISO 8601, inclusive). Applies to unit resolution time, not to when the cost was incurred.
end_datequerystringYesEnd of date range (ISO 8601, exclusive).
unresolved_after_hoursquerynumber (double)NoHours of inactivity after which a terminal-less unit is reported as unresolved rather than still running. Whole number between 1 and 8760; default 24.

Response fields

Fields returned in the 200 response body. Nested objects are listed under their parent. A field marked optional may be absent from the body; one marked nullable is always present but its value may be null.

FieldTypeDescription
itemsobject[]One item per outcome value, ordered by total unit cost descending.
outcomestringThe declared outcome value (the span's outcome option, e.g., "ticket_resolved").
completed_countnumber (double)Distinct units that completed inside the date range. Retried units (same unit_key across attempts) count once; a unit counts as completed when any of its attempts completed.
completed_coststringTotal cost of the completed units (USD, decimal string). Sums every attempt's full call-subtree cost, including failed attempts of a unit that later completed. A unit's cost may predate the date range; the range filters on when the unit RESOLVED, not on when it spent.
cost_per_completed_unitstring nullablecompleted_cost divided by completed_count (USD, decimal string). Null when completed_count is 0; a real "0" would mean completed units were free, which is a different fact than "nothing completed".
failed_countnumber (double)Distinct units whose every attempt failed inside the date range.
failed_coststringTotal cost of the failed units (USD, decimal string).
unresolved_countnumber (double)Units that declared this outcome but never reported completion or failure (for example, the process died) and have been inactive longer than unresolved_after_hours. Units still inside that inactivity window are treated as running and are not counted anywhere.
unresolved_coststringTotal cost of the unresolved units (USD, decimal string).
retried_unit_countnumber (double)Units with more than one terminal (completion or failure) event under the same unit_key. An attempt that died without emitting a terminal event (process death) contributes its cost but does not increment this counter; it surfaces through the unresolved bucket instead.
total_outcome_countnumber (double)Number of distinct outcome values in the range; equals items.length.

Error codes

Errors return the standard error envelope with a code, message, and a correlationId you can quote to support.

StatusWhen it happens
400Invalid request data. Check that start_date is before end_date, both are valid ISO 8601 dates, and unresolved_after_hours is a whole number between 1 and 8760.
401Missing or invalid API key. Send your key as Authorization: Bearer YOUR_API_KEY.
403API key lacks the costs:read scope. Create or update an API key with the costs:read scope, then retry.
429Rate limit or plan quota exceeded. Slow down and retry after the current window resets.

Rate limits and retries

Rate limit or plan quota exceeded. Slow down and retry after the current window resets.