AiCallRecordedPayload ai.call.recorded@1
Generated at from
openvibe-contracts v0.419.0 and
openvibe-sdk v0.161.0.
- Version
- 1.0.0
- Owner
- ai
- Visibility
- first-party
- Status
- active
- Compatibility
- backward
- Decision
- ADR-033
- Schema
https://openvibe.network/contracts/events/payloads/ai.call.recorded.v1.json
ai.call.recorded v1 (plan L40, one AI meter across the network). One AI call, wherever it happened: OpenVibe.AI's own runs, a harness turn in Codes, an Actor task, Vibe, a local model on a person's own machine. who and where: subject (the person, or null when the call is anonymous), attribution (the site or app the call came from, free text such as 'site:design'), surface (the product surface, free text such as 'design.generate' or 'codes.turn'). what ran: system (ai, harness:claude-code, harness:codex, actor, node), provider, model, effort. who paid: paid_by (own_key, openvibe_key, plan, own_machine, free_tier, network_allowance, org_key) and paid_by_detail (for example 'anthropic ...a1b2' for a person's own key, or 'claude-max' for a plan). tokens: input (the UNCACHED input tokens), output, reasoning, cache_read, cache_write (with cache_write_ttl 5m or 1h), images, audio_seconds, video_seconds. money, in USD: list_cost_usd (what the tokens cost at the human-typed list prices), charged_usd (what the payer was actually charged), fee_usd (the network's fee on top), cache_saved_usd (what the cache saved against the plain input price). price_source says where the prices came from ('models', 'pricing', 'flat', or 'no cache price' when no cache price is typed and the cache tokens are priced at the input price), price_date the day the price was checked. how it went: latency_ms, ttft_ms, attempts, outcome. ids: run_id or turn_id, and at. The record carries NO prompt and NO answer text, ever. A ledger (OpenVibe.AI) rolls the records up; a record consumed twice is stored once (idempotent by system and run_id or turn_id). Envelope: subject { type: run, id: <run_id> } or { type: user, id: <subject> }, visibility internal, priority low, actor service:ai.
Fields
| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
subject | string | null | The person the call was made for, or null when the call was anonymous. |
| |
attribution | string | The site or app the call came from, as '<type>:<id>' (for example 'site:design'), empty when nothing is known. |
| |
surface | string | yes | The product surface: 'design.generate', 'codes.turn', 'ai.generate'. Free text, so a new surface needs no new contract. |
|
system | string | yes | What ran: 'ai', 'harness:claude-code', 'harness:codex', 'actor', 'node'. |
|
provider | string | null |
| ||
model | string | null |
| ||
effort | string | null | The reasoning effort the call asked for, when it asked for one. |
| |
paid_by | enum | yes |
| |
paid_by_detail | string | null | Which key or plan paid, for example 'anthropic ...a1b2' or 'claude-max'. Never a whole secret. |
| |
input | integer | yes | The uncached input tokens. Cache reads and cache writes are counted on their own fields. |
|
output | integer | yes |
| |
reasoning | integer | yes |
| |
cache_read | integer | yes |
| |
cache_write | integer | yes |
| |
cache_write_ttl | enum | yes | How long the written cache entry lives, when the provider says. |
|
images | integer | yes |
| |
audio_seconds | number | yes |
| |
video_seconds | number | yes |
| |
list_cost_usd | number | yes | What the tokens cost at the human-typed list prices. |
|
charged_usd | number | yes | What the payer was actually charged. A person's own key is never charged here: 0. |
|
fee_usd | number | yes | The network's fee on top of the cost, when the OpenVibe key paid. |
|
cache_saved_usd | number | yes | What the cached tokens saved against the plain input price. |
|
price_source | string | yes | Where the prices came from: 'models' (a person's typed model row), 'pricing' (AI_PRICING_JSON), 'flat' (the flat rates), 'no cache price' (no cache price is typed, so the cache tokens are priced at the input price). |
|
price_date | string | null | yes | The day the price was checked, when it was. |
|
latency_ms | integer | null | yes |
| |
ttft_ms | integer | null | yes | Time to the first token, when the call streamed and it was measured. |
|
attempts | integer | yes |
| |
outcome | enum | yes |
| |
run_id | string | null |
| ||
turn_id | string | null |
| ||
at | string | yes |
|
Examples
From the contract's own test fixtures: valid ones validate, rejected ones must fail.
Valid: openvibe-key
{
"subject": null,
"attribution": "",
"surface": "ai.complete",
"system": "harness:claude-code",
"provider": "openai",
"model": "gpt-5",
"effort": null,
"paid_by": "openvibe_key",
"paid_by_detail": "openvibe:gpt-5",
"input": 200,
"output": 80,
"reasoning": 40,
"cache_read": 800,
"cache_write": 0,
"cache_write_ttl": null,
"images": 0,
"audio_seconds": 0,
"video_seconds": 0,
"list_cost_usd": 0.0021,
"charged_usd": 0.0021,
"fee_usd": 0.000105,
"cache_saved_usd": 0,
"price_source": "no cache price",
"price_date": null,
"latency_ms": 1800,
"ttft_ms": null,
"attempts": 2,
"outcome": "succeeded",
"run_id": null,
"turn_id": "tn_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"at": "2026-10-31T18:05:00.000Z"
}Valid: own-key
{
"subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"attribution": "site:design",
"surface": "design.generate",
"system": "ai",
"provider": "anthropic",
"model": "claude-sonnet-4-5",
"effort": "high",
"paid_by": "own_key",
"paid_by_detail": "anthropic ...a1b2",
"input": 1200,
"output": 300,
"reasoning": 0,
"cache_read": 8000,
"cache_write": 1500,
"cache_write_ttl": "5m",
"images": 0,
"audio_seconds": 0,
"video_seconds": 0,
"list_cost_usd": 0.012345,
"charged_usd": 0,
"fee_usd": 0,
"cache_saved_usd": 0.00321,
"price_source": "models",
"price_date": "2026-10-31",
"latency_ms": 4200,
"ttft_ms": 640,
"attempts": 1,
"outcome": "succeeded",
"run_id": "run_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"turn_id": null,
"at": "2026-10-31T18:00:00.000Z"
}Rejected: carries-output-text
{
"subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"attribution": "site:design",
"surface": "design.generate",
"system": "ai",
"provider": "anthropic",
"model": "claude-sonnet-4-5",
"effort": "high",
"paid_by": "own_key",
"paid_by_detail": "anthropic ...a1b2",
"input": 1200,
"output": 300,
"reasoning": 0,
"cache_read": 8000,
"cache_write": 1500,
"cache_write_ttl": "5m",
"images": 0,
"audio_seconds": 0,
"video_seconds": 0,
"list_cost_usd": 0.012345,
"charged_usd": 0,
"fee_usd": 0,
"cache_saved_usd": 0.00321,
"price_source": "models",
"price_date": "2026-10-31",
"latency_ms": 4200,
"ttft_ms": 640,
"attempts": 1,
"outcome": "succeeded",
"run_id": "run_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"turn_id": null,
"at": "2026-10-31T18:00:00.000Z",
"output_text": "the answer the model gave"
}Rejected: unknown-cache-write-ttl
{
"subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"attribution": "site:design",
"surface": "design.generate",
"system": "ai",
"provider": "anthropic",
"model": "claude-sonnet-4-5",
"effort": "high",
"paid_by": "own_key",
"paid_by_detail": "anthropic ...a1b2",
"input": 1200,
"output": 300,
"reasoning": 0,
"cache_read": 8000,
"cache_write": 1500,
"cache_write_ttl": "10m",
"images": 0,
"audio_seconds": 0,
"video_seconds": 0,
"list_cost_usd": 0.012345,
"charged_usd": 0,
"fee_usd": 0,
"cache_saved_usd": 0.00321,
"price_source": "models",
"price_date": "2026-10-31",
"latency_ms": 4200,
"ttft_ms": 640,
"attempts": 1,
"outcome": "succeeded",
"run_id": "run_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"turn_id": null,
"at": "2026-10-31T18:00:00.000Z"
}Rejected: unknown-paid-by
{
"subject": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"attribution": "site:design",
"surface": "design.generate",
"system": "ai",
"provider": "anthropic",
"model": "claude-sonnet-4-5",
"effort": "high",
"paid_by": "someone_else",
"paid_by_detail": "anthropic ...a1b2",
"input": 1200,
"output": 300,
"reasoning": 0,
"cache_read": 8000,
"cache_write": 1500,
"cache_write_ttl": "5m",
"images": 0,
"audio_seconds": 0,
"video_seconds": 0,
"list_cost_usd": 0.012345,
"charged_usd": 0,
"fee_usd": 0,
"cache_saved_usd": 0.00321,
"price_source": "models",
"price_date": "2026-10-31",
"latency_ms": 4200,
"ttft_ms": 640,
"attempts": 1,
"outcome": "succeeded",
"run_id": "run_01JAB2C3D4E5F6G7H8J9K0MNPQ",
"turn_id": null,
"at": "2026-10-31T18:00:00.000Z"
}Validate
const contracts = require('openvibe-contracts');
contracts.validate('ai.call.recorded@1', value); // { valid, errors: [{ path, message }] }