MediaUsageRecordedPayload media.usage.recorded@1

Generated at from openvibe-contracts v0.177.0 and openvibe-sdk v0.44.0.

Version
1.0.0
Owner
media
Visibility
first-party
Status
active
Compatibility
backward
Decision
ADR-014
Schema
https://openvibe.network/contracts/events/payloads/media.usage.recorded.v1.json

media.usage.recorded v1 (ADR-031 amendment 2026-10-02, section 8). One closed hour of one zone's use on OpenVibe.Media's S3 surface: resource is the zone's OVRN (ovrn:zone:<project_id>:object-zone/<zon_id>) and dimension the zone id in lowercase, on every rollup. The series: stored bytes (media.object.upload, unit byte_hours: the live objects' bytes summed over the hour, sampled each minute), writes (media.object.upload and media.object.delete, unit requests), lists (media.object.list, unit requests), reads (media.object.read, unit requests) and egress (media.object.read, unit egress_bytes). errors counts the operations refused or failed in the hour, by S3 error code mapped to media.s3.<code>. Media counts as it answers and stores the rollup as its own event after the hour closes, in the same transaction that marks the hour sent; a corrected hour is re-sent with a higher revision. Rollups are counts for dashboards and quotas, never money. The payload is common.usage-recorded@1. Envelope: source media, subject { type: project, id: <project_id> }, visibility internal, priority low, actor service:media.

Fields

This schema has no named fields.

Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

Valid: egress
{
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "env": "production",
  "resource": "ovrn:zone:prj_01JAB2C3D4E5F6G7H8J9K0MNPQ:object-zone/zon_01JAB2C3D4E5F6G7H8J9K0MNPR",
  "dimension": "zon_01jab2c3d4e5f6g7h8j9k0mnpr",
  "window": "hour",
  "window_start": "2026-10-15T10:00:00.000Z",
  "window_end": "2026-10-15T11:00:00.000Z",
  "capability": "media.object.read",
  "unit": "egress_bytes",
  "quantity": 104857600,
  "errors": 0,
  "revision": 2
}
Valid: reads-with-errors
{
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "env": "production",
  "resource": "ovrn:zone:prj_01JAB2C3D4E5F6G7H8J9K0MNPQ:object-zone/zon_01JAB2C3D4E5F6G7H8J9K0MNPR",
  "dimension": "zon_01jab2c3d4e5f6g7h8j9k0mnpr",
  "window": "hour",
  "window_start": "2026-10-15T10:00:00.000Z",
  "window_end": "2026-10-15T11:00:00.000Z",
  "capability": "media.object.read",
  "unit": "requests",
  "quantity": 420,
  "errors": 3,
  "error_codes": {
    "media.s3.no_such_key": 2,
    "media.s3.access_denied": 1
  },
  "samples": [
    {
      "at": "2026-10-15T10:42:10.000Z",
      "code": "media.s3.no_such_key",
      "status": 404
    }
  ]
}
Valid: stored-byte-hours
{
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "env": "production",
  "resource": "ovrn:zone:prj_01JAB2C3D4E5F6G7H8J9K0MNPQ:object-zone/zon_01JAB2C3D4E5F6G7H8J9K0MNPR",
  "dimension": "zon_01jab2c3d4e5f6g7h8j9k0mnpr",
  "window": "hour",
  "window_start": "2026-10-15T10:00:00.000Z",
  "window_end": "2026-10-15T11:00:00.000Z",
  "capability": "media.object.upload",
  "unit": "byte_hours",
  "quantity": 5368709120,
  "errors": 0
}
Rejected: carries-an-object-key
{
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "env": "production",
  "resource": "ovrn:zone:prj_01JAB2C3D4E5F6G7H8J9K0MNPQ:object-zone/zon_01JAB2C3D4E5F6G7H8J9K0MNPR",
  "dimension": "zon_01jab2c3d4e5f6g7h8j9k0mnpr",
  "window": "hour",
  "window_start": "2026-10-15T10:00:00.000Z",
  "window_end": "2026-10-15T11:00:00.000Z",
  "capability": "media.object.upload",
  "unit": "requests",
  "quantity": 1,
  "errors": 0,
  "object_key": "photos/me.jpg"
}
Rejected: resource-of-a-person
{
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "env": "production",
  "resource": "ovrn:network:prj_01JAB2C3D4E5F6G7H8J9K0MNPQ:account/usr_01JAB2C3D4E5F6G7H8J9K0MNPS",
  "dimension": "zon_01jab2c3d4e5f6g7h8j9k0mnpr",
  "window": "hour",
  "window_start": "2026-10-15T10:00:00.000Z",
  "window_end": "2026-10-15T11:00:00.000Z",
  "capability": "media.object.read",
  "unit": "requests",
  "quantity": 1,
  "errors": 0
}

Validate

const contracts = require('openvibe-contracts');
contracts.validate('media.usage.recorded@1', value);   // { valid, errors: [{ path, message }] }