---
title: "live.agent_stream.changed@1 · OpenVibe.Services"
canonical: "https://openvibe.services/docs/contracts/live.agent_stream.changed"
updated: null
---

# live.agent\_stream.changed@1 · OpenVibe.Services

HTML: [live.agent\_stream.changed@1 · OpenVibe.Services](https://openvibe.services/docs/contracts/live.agent_stream.changed)

# LiveAgentStreamChangedPayload `live.agent_stream.changed@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: live
- Visibility: first-party
- Status: active
- Compatibility: backward
- Schema: [`https://openvibe.network/contracts/events/payloads/live.agent_stream.changed.v1.json`](/docs/contracts/live.agent_stream.changed.json)

live.agent\_stream.changed v1 (OpenVibe.Live, the Agent Streams plan, S1): an agent stream changed. KIND is what happened: started, ended, visibility (the owner switched it) or curtain (the desk's privacy screen went up or came down). It says what happened and never why: the curtain's reason stays with the owner, so a subscriber learns that a private screen is up, not that a password field was focused. VISIBILITY carries the new visibility when KIND is visibility, CURTAIN whether the screen is up when KIND is curtain. The publish ticket, the stream key and the task's contents never appear. Envelope: subject { type: agent\_stream, id: ags\_… }, actor the owner's subject when Live knows it, else service:live. The event type carries no hyphen (events.event-envelope@1's event\_type pattern allows letters, digits and underscores only), so it is live.agent\_stream.changed; the stream's contract ids keep live.agent-stream@1.

## Fields

| Field | Type | Required | Description | Constraints |
| --- | --- | --- | --- | --- |
| `stream_id` | string | yes |  | - `pattern ^ags_[0-9A-HJKMNP-TV-Z]{26}$` |
| `kind` | enum | yes |  | - `one of "started", "ended", "visibility", "curtain"` |
| `visibility` | enum |  | The new visibility, when KIND is visibility. | - `one of "private", "unlisted", "public"` |
| `curtain` | object |  | Whether the privacy screen is up, when KIND is curtain. Never the reason. | - `no other fields` |
| `curtain.up` | boolean | yes |  |  |
| `at` | string | yes |  | - `format date-time` |

## Examples

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

 Valid: curtain

~~~~
{
  "stream_id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "kind": "curtain",
  "curtain": {
    "up": true
  },
  "at": "2026-11-06T12:05:00.000Z"
}
~~~~

Valid: started

~~~~
{
  "stream_id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "kind": "started",
  "at": "2026-11-06T12:00:00.000Z"
}
~~~~

Valid: visibility

~~~~
{
  "stream_id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "kind": "visibility",
  "visibility": "unlisted",
  "at": "2026-11-06T12:10:00.000Z"
}
~~~~

Rejected: carries-the-curtain-reason

~~~~
{
  "stream_id": "ags_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "kind": "curtain",
  "curtain": {
    "up": true,
    "reason": "password_field"
  },
  "at": "2026-11-06T12:05:00.000Z"
}
~~~~

## Validate

~~~~
const contracts = require('openvibe-contracts');
contracts.validate('live.agent_stream.changed@1', value);   // { valid, errors: [{ path, message }] }
~~~~
