v0.1.2Latest · also at /spec/v0.1.2 · GitHub

Open Agent Spend Attribution (OASA) Specification

Version 0.1.2 · Published 2026-09-14 · Revised 2026-10-08 · CC BY 4.0

Abstract

OASA defines a canonical record format for agent spend attribution: attributing AI-agent resource consumption and spend to agent identity, task, and cost object, and joining runtime telemetry, normalized billing, and payment settlement into a single auditable ledger — a system of record for agent spend. It is designed to interoperate with OpenTelemetry GenAI semantic conventions (telemetry), the FOCUS specification (billing), and x402 payment-rail records (settlement). It is not a payment protocol and not a billing format; it is the join between settlement, billing, and attribution.

Partial records are valid. Every field outside the envelope is optional so adapters can emit what they know and reconcile later. Within a major version, the schema is additive-only.

OASA is the record format behind FinOps for agentic AI.

Design principles

  • Hub-and-spoke: canonical middle, adapters at the edges.
  • Settlement-agnostic: invoice, card, wire, and on-chain rails reconcile into the same spine.
  • Additive to FOCUS and OpenTelemetry — never competing with them.
  • Envelope required; all other groups optional so partial records remain valid.
  • Versioned; additive-only within a major version.

The three-layer model

TelemetryOTel GenAIAttributionOASA (canonical)BillingFOCUS+ Settlement (x402)trace_idinvoice_id + source_record_idsettlement_refHub-and-spoke: one canonical middle, adapters at the edges
Join keys on the edges; attribution in the middle.

Record schema v0.1.2

Group 1 — Envelope (required)

FieldTypeRequiredDescription
record_idstring (UUIDv7)YesGlobally unique record identifier. Adapters with a stable source key SHOULD derive it deterministically (see Deterministic record IDs) so that a retried export produces the same ID.
record_typeenum: usage | charge | settlement | allocation | outcomeYesOne row = one event class.
schema_versionstringYesSchema version string; "0.1" for this draft.
occurred_attimestamp (RFC 3339, UTC)YesWhen the event happened.
recorded_attimestamp (RFC 3339, UTC)YesWhen the record was ingested.
source_systemstringYese.g. otel-collector, openai-billing, x402-facilitator.
source_record_idstringYesKey in the source system.
currencystringYesISO 4217, or CAIP-19 asset ID for on-chain assets.

Group 2 — Agent identity

FieldTypeRequiredDescription
agent_idstringNoStable internal agent ID.
agent_namestringNoHuman-readable agent name.
agent_versionstringNoAgent build or prompt version.
agent_ownerstringNoTeam or principal accountable.
parent_agent_idstringNoParent in a sub-agent chain.
agent_frameworkstringNoe.g. langgraph, crewai, custom.
identity_schemeenum: internal | erc8004 | otherNoHow external identity is named.
external_identity_refstringNoe.g. ERC-8004 registration reference.

Group 3 — Task & session context

FieldTypeRequiredDescription
session_idstringNoRuntime session identifier.
trace_idstringNoW3C Trace Context / OpenTelemetry trace id.
span_idstringNoSpan id within the trace.
task_idstringNoOrg-defined task identifier.
task_typestringNoFree taxonomy; org-defined.
workflow_idstringNoWorkflow or pipeline id.
triggerenum: human | scheduled | agent | eventNoWhat started the run.
initiating_principalstringNoHuman or agent that authorized the run.

Group 4 — Consumption

FieldTypeRequiredDescription
providerstringNoModel or API provider.
servicestringNoService product name.
modelstringNoModel identifier.
operationenum: chat | completion | embeddings | tool_call | inference | storage | api_call | otherNoOperation class.
input_tokensintegerNoInput token count.
output_tokensintegerNoOutput token count.
cached_tokensintegerNoCached / reused tokens when reported.
reasoning_tokensintegerNoReasoning tokens when reported.
unit_typeenum: tokens | requests | seconds | gb | customNoUnit of consumption.
units_consumeddecimalNoQuantity in unit_type.
tool_namestringNoTool invoked, if any.
request_countintegerNoRequest count for the event.

Group 5 — Cost

FieldTypeRequiredDescription
list_costdecimalNoList price; mirrors FOCUS ListCost semantics.
billed_costdecimalNoBilled amount; mirrors FOCUS BilledCost.
effective_costdecimalNoEffective cost after discounts; mirrors FOCUS EffectiveCost.
cost_sourceenum: measured | rated | invoiced | allocatedNoHow cost was derived. allocated means the cost was assigned from a shared cost by an allocation rule rather than metered, rated, or invoiced for this record.
pricing_refstringNoPrice-sheet row ID.
invoice_idstringNoVendor invoice identifier.
focus_charge_refstringNoPointer into a FOCUS dataset row.

Group 6 — Allocation

FieldTypeRequiredDescription
cost_centerstringNoCost center or department.
project_idstringNoProject identifier.
customer_idstringNoCustomer or account identifier.
product_linestringNoProduct line.
environmentenum: prod | staging | dev | otherNoRuntime environment.
tagsmap<string,string>NoFree-form tags.
allocation_methodenum: direct | rule | splitNoHow cost was allocated.
allocation_rule_idstringNoRule that produced the allocation.
split_fractiondecimal (0–1)NoShare of a split allocation.

Group 7 — Settlement join

FieldTypeRequiredDescription
settlement_railenum: invoice | card | ach | wire | x402 | other_onchainNoHow money moved.
settlement_networkstringNoCAIP-2 chain ID where applicable.
settlement_assetstringNoCAIP-19 asset identifier.
settlement_amountdecimalNoSettled amount.
settlement_refstringNoTx hash, statement line, or remittance ID.
settled_attimestampNoSettlement timestamp.
reconciliation_statusenum: unmatched | matched | partial | disputedNoJoin status against billing/telemetry.

Group 8 — Control & governance

FieldTypeRequiredDescription
budget_idstringNoBudget that constrained or funded the spend.
policy_idstringNoPolicy identifier.
authorization_refstringNoMandate / verifiable-intent credential ID.
approval_typeenum: policy_auto | pre_authorized | human_approvedNoHow spend was authorized.

Group 9 — Outcome (optional, forward-looking)

Outcome capture is intentionally minimal in v0.1; it exists so cost-per-outcome queries have a landing zone.

FieldTypeRequiredDescription
outcome_event_idstringNoLinked outcome event.
outcome_typestringNoOutcome class (org-defined).
outcome_valuedecimalNoNumeric outcome value.
outcome_unitstringNoUnit for outcome_value.
business_metric_refstringNoPointer to a business metric definition.

Deterministic record IDs

Receivers deduplicate on record_id. An adapter that generates a fresh random ID on every attempt turns each retry into a duplicate row. Adapters whose source has a stable key SHOULD derive record_id from it with the procedure below; two implementations given the same inputs then produce the same ID, and the result is still a valid UUIDv7 under RFC 9562.

Inputs: occurred_at and source_record_id of the record being emitted.

  1. ms = occurred_at as Unix time in milliseconds, truncated (not rounded) to the millisecond.
  2. h = SHA-256 of the UTF-8 bytes of source_record_id.
  3. Build 16 bytes b: b[0..5] = ms as a 48-bit big-endian integer; b[6] = 0x70 | (h[0] & 0x0F) (version 7); b[7] = h[1]; b[8] = 0x80 | (h[2] & 0x3F) (RFC 9562 variant); b[9..15] = h[3..9].
  4. Format b as a lowercase hyphenated UUID string (8-4-4-4-12).

For OpenTelemetry spans, source_record_id is the trace ID and span ID in lowercase hex joined by a slash (trace_id/span_id), and occurred_at is the span end time.

Test vector: occurred_at = 2026-09-01T15:04:05Z, source_record_id = 4bf92f3577b34da6a3ce929d0e0e4736/00f067aa0ba902b7 → record_id = 01a05d7f-b288-7532-8207-8cb53896d9e1.

Derived IDs are predictable from their inputs. They are identifiers, not secrets, and MUST NOT be used as access tokens.

Machine-readable schema

The record tables above are published as JSON Schema (draft 2020-12) for adapters to validate their output: the record schema (one record, schema_version 0.1.x), the batch schema (a batch header plus an array of records), and golden examples that validate against the record schema.

Schema identifiers ($id) live under https://oasaspec.org/schema/0.1/ and never change once published; consumers may reference them directly. The schema is generated from the specification text and never edited by hand, and CI fails if the committed schema drifts from these tables.

Decimal fields, including every money field, are JSON numbers. Consumers SHOULD parse them with decimal precision rather than binary floating point.

The schema files, examples, and scripts are licensed Apache-2.0; the specification text remains CC BY 4.0. The 0.2.0 draft is not covered yet; it gets its own schema when 0.2.0 is published.

Batch envelope

Adapters that send records in bulk wrap them in this header. Every record in records is validated independently; the header carries no attribution.

FieldTypeRequiredDescription
schema_versionstringYesSchema version of the records in the batch; "0.1" for this draft.
source_systemstringYesSystem that emitted the batch, e.g. otel-collector.
emitted_attimestamp (RFC 3339, UTC)YesWhen the batch was sent.
countintegerYesNumber of records in records.
recordsarray of recordsYesOASA records, each valid against the record schema.

Mapping tables

OpenTelemetry GenAI and x402 mappings verified against upstream docs on 2026-09-15; FOCUS columns verified against focus.finops.org on 2026-10-05. OpenTelemetry GenAI conventions are still experimental and may drift; attribute names here are current as of their date, and unmapped OASA fields are noted where no ratified equivalent exists. FOCUS token-economics columns track 1.4 (ratified) and 1.5 (scheduled). x402 V2 communicates requirements via PAYMENT-REQUIRED payloads (network, asset, amount, payTo).

OASA ↔ OpenTelemetry GenAI

OASAOTelNotes
providergen_ai.provider.name
input_tokensgen_ai.usage.input_tokens
output_tokensgen_ai.usage.output_tokens
cached_tokensgen_ai.usage.cache_read.input_tokensCached/reused input tokens. Where a provider reports cache reads separately, map the cache-read count here; do not double-count into input_tokens if the provider already reports them inclusively. OTel also defines gen_ai.usage.cache_creation.input_tokens for cache writes.
reasoning_tokensgen_ai.usage.reasoning.output_tokensOutput tokens used for reasoning (e.g. chain-of-thought). OTel says this value SHOULD be included in gen_ai.usage.output_tokens. Where a provider reports reasoning only in billing payloads, populate from the provider usage object.
modelgen_ai.request.modelThe requested model. Where a provider returns a resolved or versioned model, prefer that value and record the requested model in tags if both matter.
operationgen_ai.operation.name
tool_namegen_ai.tool.nameEmitted on tool-execution spans. Pair with operation = tool_call.
session_idgen_ai.conversation.idWhere a runtime emits a conversation/thread identifier. OASA session_id is broader — a non-conversational agent run is still a session.
agent_idgen_ai.agent.id
agent_namegen_ai.agent.name
trace_id / span_idW3C Trace Context / OTel trace_id, span_idJoin key to the Attribution layer; carried from W3C Trace Context.

OASA ↔ FOCUS

FOCUS, the FinOps Foundation's open billing specification, added token-economics columns in 1.4; FOCUS 1.5 (Dec 2026 target) adds native token tracking and a Price Sheet dataset. OASA tracks those columns as they ratify.

OASAFOCUS
list_costListCost
billed_costBilledCost
effective_costEffectiveCost
providerServiceProviderName (FOCUS 1.4; formerly ProviderName)
serviceServiceName
tagsTags
charge rows (record_type=charge)ChargeCategory / charge rows

Full column-by-column mapping, including the Invoice Detail dataset and worked examples: OASA ↔ FOCUS 1.4 mapping.

OASA ↔ x402

OASAx402
settlement_networkPaymentRequired.network (PAYMENT-REQUIRED)
settlement_assetPaymentRequired asset / token
settlement_amountPaymentRequired amount / price
settlement_refon-chain tx / SettlementResponse reference
(payee context)PaymentRequired.payTo

Worked example

One agent tool-call as a usage row, later joined by a charge row and an x402 settlement row sharing trace_id / settlement_ref.

1. Usage (telemetry)

{
  "record_id": "0193f0a0-0000-7000-8000-000000000001",
  "record_type": "usage",
  "schema_version": "0.1",
  "occurred_at": "2026-09-01T15:04:05Z",
  "recorded_at": "2026-09-01T15:04:06Z",
  "source_system": "otel-collector",
  "source_record_id": "span-9f2c",
  "currency": "USD",
  "agent_id": "agent-support-47",
  "agent_name": "Support Triage",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "span_id": "00f067aa0ba902b7",
  "task_type": "ticket_resolve",
  "provider": "openai",
  "model": "gpt-4.1",
  "operation": "tool_call",
  "tool_name": "crm.lookup",
  "input_tokens": 1200,
  "output_tokens": 340,
  "cached_tokens": 800,
  "session_id": "sess-2f91",
  "unit_type": "tokens",
  "units_consumed": 1540,
  "cost_source": "measured"
}

2. Charge (billing)

{
  "record_id": "0193f0a0-0000-7000-8000-000000000002",
  "record_type": "charge",
  "schema_version": "0.1",
  "occurred_at": "2026-09-02T00:00:00Z",
  "recorded_at": "2026-09-02T06:12:00Z",
  "source_system": "openai-billing",
  "source_record_id": "inv_line_88421",
  "currency": "USD",
  "agent_id": "agent-support-47",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "invoice_id": "INV-2026-09-01",
  "focus_charge_ref": "focus:row:88421",
  "list_cost": 0.042,
  "billed_cost": 0.038,
  "effective_cost": 0.038,
  "cost_source": "invoiced"
}

3. Settlement (x402)

{
  "record_id": "0193f0a0-0000-7000-8000-000000000003",
  "record_type": "settlement",
  "schema_version": "0.1",
  "occurred_at": "2026-09-01T15:04:07Z",
  "recorded_at": "2026-09-01T15:04:08Z",
  "source_system": "x402-facilitator",
  "source_record_id": "pay_0xabc…",
  "currency": "eip155:8453/erc20:0x…",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "settlement_rail": "x402",
  "settlement_network": "eip155:8453",
  "settlement_asset": "eip155:8453/erc20:0x…",
  "settlement_amount": 0.038,
  "settlement_ref": "0xdeadbeef…",
  "settled_at": "2026-09-01T15:04:07Z",
  "reconciliation_status": "matched"
}

References

Upstream specifications and standards this document maps to or depends on.

ReferenceStewardLink
OpenTelemetry GenAI semantic conventionsOpenTelemetry (CNCF)opentelemetry.io/docs/specs/semconv/gen-ai/
FOCUS™ (FinOps Open Cost and Usage Specification)FinOps Foundation (Linux Foundation)focus.finops.org/
x402x402 Foundation (Linux Foundation)x402.org/
W3C Trace ContextW3Cwww.w3.org/TR/trace-context/
CAIP-2 (chain ID) / CAIP-19 (asset ID)Chain Agnostic Standards Alliancechainagnostic.org/
ERC-8004 (agent identity)Ethereumeips.ethereum.org/
RFC 3339 (timestamps)IETFwww.rfc-editor.org/rfc/rfc3339
ISO 4217 (currency codes)ISOwww.iso.org/iso-4217-currency-codes.html
UUIDv7 (RFC 9562)IETFwww.rfc-editor.org/rfc/rfc9562

Referencing these specifications does not imply endorsement by their stewards. OASA is an independent publication of Onaro (BrianOnAI LLC).

Changelog

  • v0.1.2 (2026-10-08) — Adds allocated to cost_source. Adds machine-readable JSON Schema, golden examples and validation tooling. Documents deterministic record IDs. FOCUS mapping: provider maps to ServiceProviderName (FOCUS 1.4; formerly ProviderName). No fields added, removed, or renamed; schema_version remains "0.1".
  • v0.1.1 (2026-09-15) — Extended the OpenTelemetry GenAI mapping with tool, cached-token, conversation, and reasoning attributes; added a Notes column. Mapped cached_tokens to gen_ai.usage.cache_read.input_tokens (registry name as of 2026-09-15). No schema fields added, removed, or renamed; schema_version remains "0.1".
  • v0.1 (2026-09-14) — initial public draft.

Contributing

The specification is developed in the open at github.com/onaro-io/agent-spend-attribution. Open an issue for anything wrong, missing, or ambiguous — especially an upstream attribute name that has drifted — or a pull request against SPEC.md for concrete changes. Implementation reports are the most useful contribution: if you have tried to map real agent spend with this schema, what broke is what the next version needs to fix.

General comments: hello@onaro.io

Cite this specification

Open Agent Spend Attribution (OASA) Specification, version 0.1.2 (rev. 2026-10-08). Onaro. https://www.onaro.io/spec

Repository: https://github.com/onaro-io/agent-spend-attribution

License: CC BY 4.0. Attribution required; adaptations allowed.

Related: The Missing Ledger · Agent spend attribution · Agent payment data