---
title: "ai.call.recorded@1 · OpenVibe.Services"
canonical: "https://openvibe.services/docs/contracts/ai.call.recorded"
updated: null
---

# ai.call.recorded@1 · OpenVibe.Services

HTML: [ai.call.recorded@1 · OpenVibe.Services](https://openvibe.services/docs/contracts/ai.call.recorded)

# AiCallRecordedPayload `ai.call.recorded@1`

Generated at 2026-11-13 06:25:48 UTC from [`openvibe-contracts v0.419.0`](https://github.com/OpenVibers/OpenVibe.Contracts/tree/v0.419.0) and [`openvibe-sdk v0.161.0`](https://github.com/OpenVibers/OpenVibe.SDK/tree/v0.161.0).

- Version: 1.0.0
- Owner: ai
- Visibility: first-party
- Status: active
- Compatibility: backward
- Decision: [ADR-033](/docs/adr/ADR-033)
- Schema: [`https://openvibe.network/contracts/events/payloads/ai.call.recorded.v1.json`](/docs/contracts/ai.call.recorded.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. | - `maxLength 128` |
| `attribution` | string |  | The site or app the call came from, as '<type>:<id>' (for example 'site:design'), empty when nothing is known. | - `maxLength 200` |
| `surface` | string | yes | The product surface: 'design.generate', 'codes.turn', 'ai.generate'. Free text, so a new surface needs no new contract. | - `maxLength 200` |
| `system` | string | yes | What ran: 'ai', 'harness:claude-code', 'harness:codex', 'actor', 'node'. | - `maxLength 100` |
| `provider` | string \| null |  |  | - `maxLength 128` |
| `model` | string \| null |  |  | - `maxLength 200` |
| `effort` | string \| null |  | The reasoning effort the call asked for, when it asked for one. | - `maxLength 64` |
| `paid_by` | enum | yes |  | - `one of "own_key", "openvibe_key", "plan", "own_machine", "free_tier", "network_allowance", "org_key"` |
| `paid_by_detail` | string \| null |  | Which key or plan paid, for example 'anthropic ...a1b2' or 'claude-max'. Never a whole secret. | - `maxLength 200` |
| `input` | integer | yes | The uncached input tokens. Cache reads and cache writes are counted on their own fields. | - `minimum 0` |
| `output` | integer | yes |  | - `minimum 0` |
| `reasoning` | integer | yes |  | - `minimum 0` |
| `cache_read` | integer | yes |  | - `minimum 0` |
| `cache_write` | integer | yes |  | - `minimum 0` |
| `cache_write_ttl` | enum | yes | How long the written cache entry lives, when the provider says. | - `one of "5m", "1h", null` |
| `images` | integer | yes |  | - `minimum 0` |
| `audio_seconds` | number | yes |  | - `minimum 0` |
| `video_seconds` | number | yes |  | - `minimum 0` |
| `list_cost_usd` | number | yes | What the tokens cost at the human-typed list prices. | - `minimum 0` |
| `charged_usd` | number | yes | What the payer was actually charged. A person's own key is never charged here: 0. | - `minimum 0` |
| `fee_usd` | number | yes | The network's fee on top of the cost, when the OpenVibe key paid. | - `minimum 0` |
| `cache_saved_usd` | number | yes | What the cached tokens saved against the plain input price. | - `minimum 0` |
| `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). | - `maxLength 64` |
| `price_date` | string \| null | yes | The day the price was checked, when it was. | - `pattern ^[0-9]{4}-[0-9]{2}-[0-9]{2}$` |
| `latency_ms` | integer \| null | yes |  | - `minimum 0` |
| `ttft_ms` | integer \| null | yes | Time to the first token, when the call streamed and it was measured. | - `minimum 0` |
| `attempts` | integer | yes |  | - `minimum 0` |
| `outcome` | enum | yes |  | - `one of "succeeded", "failed", "cancelled", "cached"` |
| `run_id` | string \| null |  |  | - `maxLength 100` |
| `turn_id` | string \| null |  |  | - `maxLength 100` |
| `at` | string | yes |  | - `format date-time` |

## 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 }] }
~~~~
