NetworkConsent network.consent@1
Generated at from
openvibe-contracts v0.419.0 and
openvibe-sdk v0.161.0.
- Version
- 1.0.0
- Owner
- network
- Visibility
- public
- Status
- active
- Compatibility
- backward
- Schema
https://openvibe.network/contracts/network/consent.v1.json
network.consent@1 (L24, data and AI by consent, 2026-10-31): one person's choice for one purpose. Nothing a person makes is off-limits to AI or data use by design; each use is off until that person turns it on, here. The record is the proof of what was allowed, by whom, under which wording and when: a choice is turned off by setting revoked_at, never by deleting the row. Stored by OpenVibe.Network (consents, with every change in consent_events), read by a person at GET /api/v1/me/consent and by services through POST /internal/consent/check (capability network.consent.read). A service that cannot reach Network treats every purpose as off.
Fields
| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
id | string | yes | The choice's own id (cns_<ULID>). A choice changed later (other kinds, another licence) is a new record; the old one is revoked. |
|
subject | string | yes | Whose choice it is. Only that person (or an account merge or deletion) changes it. |
|
purpose | enum | yes | What turning it on allows. ai.train: OpenVibe trains or fine-tunes models on the person's content. data.public: the person's content goes into OpenVibe's open dataset under the licence in options. face.recognize: the person's face is recognised (the features in options; OpenVibe.Vision keeps the encrypted templates). ai.looks is retired (0.256.0): the owner removed the rule that AI text never describes people (2026-10-31), so describing how someone looks needs no opt-in; it stays in the list so older readers still validate, and nothing writes it. app.data: one named app (client) may use the person's content for the purposes in options. |
|
on | boolean | yes | Whether the purpose is allowed now: true while the record is active (revoked_at null and expires_at not passed). A service never decides from this field alone; it asks the check. | |
kinds | array of enum | yes | Which of the person's content it covers. Empty means every kind the purpose applies to. face.recognize and ai.looks take no kinds (they are about the person, not a piece of content). |
|
client | string | null | yes | The app the choice is for: null means OpenVibe itself; otherwise the OAuth client id of the app the person granted it to. app.data always names one. Since 0.310.0 an app may ask for any purpose at sign-in (consent:<purpose>, network.consent-claim@1): the grant is one record per purpose with this client and source oauth, and it allows that app only, never OpenVibe itself or another app. |
|
options | object | yes | What the purpose needs beyond on and kinds. An empty object for ai.train and ai.looks. |
|
options.licence | enum | data.public only: the licence the person's content is published under. |
| |
options.features | array of enum | face.recognize only: which recognition the person allows (OpenVibe.Vision's features). Empty means none yet. |
| |
options.purposes | array of enum | app.data only, and not written since 0.310.0: an app's consent screen grants each purpose as its own record (client set), so a reader asks for the purpose itself. Kept so older records still validate. |
| |
text_version | string | yes | The exact wording the person saw when choosing (YYYY-MM-DD.n). A new wording never turns an existing choice on; it may only ask again. |
|
source | enum | yes | Where the choice was made: the account page, an app's consent screen at sign-in (consent:<purpose>, with client set), the person's own API call, or OpenVibe.Vision's older face consents moved into Network. |
|
granted_at | string | yes | When the person turned it on. |
|
revoked_at | string | null | yes | When it was turned off (by the person, by revoking the app, by a merge or by deleting the account), or null while it holds. Use stops on the next check; a model already trained keeps what it learned, and the next dataset release leaves the person's content out. |
|
expires_at | string | null | yes | When the choice ends by itself (a time-limited grant, or the end of a face purpose), or null for no end. |
|
Examples
From the contract's own test fixtures: valid ones validate, rejected ones must fail.
Valid: ai-train-streams
{
"id": "cns_01K6R3A1B2C3D4E5F6G7H8J9KA",
"subject": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
"purpose": "ai.train",
"on": true,
"kinds": [
"streams",
"vods"
],
"client": null,
"options": {},
"text_version": "2026-10-31.1",
"source": "account",
"granted_at": "2026-10-31T05:00:00.000Z",
"revoked_at": null,
"expires_at": null
}Valid: app-data-revoked
{
"id": "cns_01K6R3A1B2C3D4E5F6G7H8J9KC",
"subject": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
"purpose": "app.data",
"on": false,
"kinds": [
"pictures"
],
"client": "app_01K6R3A1B2C3D4E5F6G7H8J9KD",
"options": {
"purposes": [
"ai.train"
]
},
"text_version": "2026-10-31.1",
"source": "oauth",
"granted_at": "2026-10-31T05:00:00.000Z",
"revoked_at": "2026-11-02T08:00:00.000Z",
"expires_at": null
}Valid: face-recognize
{
"id": "cns_01K6R3A1B2C3D4E5F6G7H8J9KB",
"subject": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
"purpose": "face.recognize",
"on": true,
"kinds": [],
"client": null,
"options": {
"features": [
"verify",
"library"
]
},
"text_version": "2026-10-31.1",
"source": "import:vision",
"granted_at": "2026-10-31T05:00:00.000Z",
"revoked_at": null,
"expires_at": "2027-10-31T05:00:00.000Z"
}Valid: oauth-app-train
{
"id": "cns_01K9A3A1B2C3D4E5F6G7H8J9KC",
"subject": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
"purpose": "ai.train",
"on": true,
"kinds": [],
"client": "app_01K6R3A1B2C3D4E5F6G7H8J9KD",
"options": {},
"text_version": "2026-11-07.1",
"source": "oauth",
"granted_at": "2026-11-07T05:00:00.000Z",
"revoked_at": null,
"expires_at": null
}Rejected: bad-id
{
"id": "cns_123",
"subject": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
"purpose": "ai.train",
"on": true,
"kinds": [
"streams",
"vods"
],
"client": null,
"options": {},
"text_version": "2026-10-31.1",
"source": "account",
"granted_at": "2026-10-31T05:00:00.000Z",
"revoked_at": null,
"expires_at": null
}Rejected: unknown-purpose
{
"id": "cns_01K6R3A1B2C3D4E5F6G7H8J9KA",
"subject": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
"purpose": "data.sell",
"on": true,
"kinds": [
"streams",
"vods"
],
"client": null,
"options": {},
"text_version": "2026-10-31.1",
"source": "account",
"granted_at": "2026-10-31T05:00:00.000Z",
"revoked_at": null,
"expires_at": null
}Validate
const contracts = require('openvibe-contracts');
contracts.validate('network.consent@1', value); // { valid, errors: [{ path, message }] }