openvibers/openvibe.contracts Commits

v0.15.0: OpenVibe.Tips is alpha (tips.* capabilities); Live gains live.tips_delivery.write

OP OpenVibers committed 23 Sept 2026 · a5aede3cd6 · 21 files, +411 −11


Changes

ddiff --git a/manifests/capabilities/live.tips_delivery.write.json b/manifests/capabilities/live.tips_delivery.write.json
nnew file mode 100644
iindex 00000000..0c84fe69
---- /dev/null
++++ b/manifests/capabilities/live.tips_delivery.write.json
@@@ -0,0 +1,19 @@
++{
++ "id": "live.tips_delivery.write",
++ "version": "1.0",
++ "owner": "live",
++ "status": "active",
++ "visibility": "internal",
++ "description": "OpenVibe.Tips' live-chat adapter: announce a settled tip in the creator's Live chat (donation line, paid message, TTS, media request at no charge). Owned by Live (docs/live-patch.diff adds the route); proposed here for Live's manifest.",
++ "permissions": [
++ "live:chat"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "standard",
++ "events": [],
++ "implementedBy": [
++ "POST /internal/tips/deliveries"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.checkout.create.json b/manifests/capabilities/tips.checkout.create.json
nnew file mode 100644
iindex 00000000..fa434eb6
---- /dev/null
++++ b/manifests/capabilities/tips.checkout.create.json
@@@ -0,0 +1,22 @@
++{
++ "id": "tips.checkout.create",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Start a tip for a supporter (on_behalf SubjectRef): paid from the supporter's Billing credit (billing.transfer.create) or through a Billing checkout intent (billing.intent.create). Tips never prices money; Billing does. Idempotent by Idempotency-Key.",
++ "permissions": [
++ "tips:checkout"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "payments",
++ "events": [
++ "tips.interaction.ready",
++ "tips.interaction.cancelled"
++ ],
++ "implementedBy": [
++ "POST /api/v1/checkout"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.goal.close.json b/manifests/capabilities/tips.goal.close.json
nnew file mode 100644
iindex 00000000..39e7ba44
---- /dev/null
++++ b/manifests/capabilities/tips.goal.close.json
@@@ -0,0 +1,21 @@
++{
++ "id": "tips.goal.close",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Close a goal; its history stays.",
++ "permissions": [
++ "tips:goals"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "standard",
++ "events": [
++ "tips.goal.updated"
++ ],
++ "implementedBy": [
++ "POST /api/v1/goals/:id/close"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.goal.create.json b/manifests/capabilities/tips.goal.create.json
nnew file mode 100644
iindex 00000000..8b84cc73
---- /dev/null
++++ b/manifests/capabilities/tips.goal.create.json
@@@ -0,0 +1,21 @@
++{
++ "id": "tips.goal.create",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Create a goal for a creator. Goal totals are derived from settled interactions only.",
++ "permissions": [
++ "tips:goals"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "standard",
++ "events": [
++ "tips.goal.updated"
++ ],
++ "implementedBy": [
++ "POST /api/v1/goals"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.goal.update.json b/manifests/capabilities/tips.goal.update.json
nnew file mode 100644
iindex 00000000..bb230ff0
---- /dev/null
++++ b/manifests/capabilities/tips.goal.update.json
@@@ -0,0 +1,22 @@
++{
++ "id": "tips.goal.update",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Edit a goal (title, target, description, image, order) with optimistic revision checks; read private goals with contributions.",
++ "permissions": [
++ "tips:goals"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "standard",
++ "events": [
++ "tips.goal.updated"
++ ],
++ "implementedBy": [
++ "PATCH /api/v1/goals/:id",
++ "GET /api/v1/goals/:id"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.interaction.get.json b/manifests/capabilities/tips.interaction.get.json
nnew file mode 100644
iindex 00000000..93772966
---- /dev/null
++++ b/manifests/capabilities/tips.interaction.get.json
@@@ -0,0 +1,19 @@
++{
++ "id": "tips.interaction.get",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Read one interaction with its separate payment state (from Billing) and delivery state (effects).",
++ "permissions": [
++ "tips:interactions"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "standard",
++ "events": [],
++ "implementedBy": [
++ "GET /api/v1/interactions/:id"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.interaction.list.json b/manifests/capabilities/tips.interaction.list.json
nnew file mode 100644
iindex 00000000..774edd10
---- /dev/null
++++ b/manifests/capabilities/tips.interaction.list.json
@@@ -0,0 +1,20 @@
++{
++ "id": "tips.interaction.list",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "List a creator's or a supporter's interactions and a creator's derived totals.",
++ "permissions": [
++ "tips:interactions"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "standard",
++ "events": [],
++ "implementedBy": [
++ "GET /api/v1/interactions",
++ "GET /api/v1/profiles/:creator/totals"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.interaction.record.json b/manifests/capabilities/tips.interaction.record.json
nnew file mode 100644
iindex 00000000..0d0382cf
---- /dev/null
++++ b/manifests/capabilities/tips.interaction.record.json
@@@ -0,0 +1,21 @@
++{
++ "id": "tips.interaction.record",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "internal",
++ "description": "Record a tip that never touched OpenVibe money (ADR-012 EXTERNAL: a tip on a creator's own PowerChat) once per (provider, provider_ref); no Billing liability, excluded from Billing reconciliation. Not in the charter list: proposed because EXTERNAL tips need a recording path while Billing emits nothing for them.",
++ "permissions": [
++ "tips:interactions"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "standard",
++ "events": [
++ "tips.interaction.ready"
++ ],
++ "implementedBy": [
++ "POST /api/v1/interactions/external"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.media_request.create.json b/manifests/capabilities/tips.media_request.create.json
nnew file mode 100644
iindex 00000000..dca51566
---- /dev/null
++++ b/manifests/capabilities/tips.media_request.create.json
@@@ -0,0 +1,21 @@
++{
++ "id": "tips.media_request.create",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Start a paid media request for a supporter (allowed hosts, the creator's minimum and length); queued with the media-queue owner only after settlement.",
++ "permissions": [
++ "tips:checkout"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "payments",
++ "events": [
++ "tips.interaction.ready"
++ ],
++ "implementedBy": [
++ "POST /api/v1/media-requests"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.overlay.config.get.json b/manifests/capabilities/tips.overlay.config.get.json
nnew file mode 100644
iindex 00000000..7ba93106
---- /dev/null
++++ b/manifests/capabilities/tips.overlay.config.get.json
@@@ -0,0 +1,20 @@
++{
++ "id": "tips.overlay.config.get",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Read a creator's overlay configs (alert and goal display settings).",
++ "permissions": [
++ "tips:overlays"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "standard",
++ "events": [],
++ "implementedBy": [
++ "GET /api/v1/overlay-configs",
++ "GET /api/v1/overlay-configs/:id"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.overlay.config.update.json b/manifests/capabilities/tips.overlay.config.update.json
nnew file mode 100644
iindex 00000000..6a856684
---- /dev/null
++++ b/manifests/capabilities/tips.overlay.config.update.json
@@@ -0,0 +1,20 @@
++{
++ "id": "tips.overlay.config.update",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Create or change a creator's overlay configs; open overlays receive the change at once.",
++ "permissions": [
++ "tips:overlays"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "standard",
++ "events": [],
++ "implementedBy": [
++ "POST /api/v1/overlay-configs",
++ "PATCH /api/v1/overlay-configs/:id"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.overlay.token.create.json b/manifests/capabilities/tips.overlay.token.create.json
nnew file mode 100644
iindex 00000000..ce788b8d
---- /dev/null
++++ b/manifests/capabilities/tips.overlay.token.create.json
@@@ -0,0 +1,20 @@
++{
++ "id": "tips.overlay.token.create",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Mint a scoped overlay token (alerts, goals) for a creator — shown once, stored hashed, never a creator cookie — and list a creator's tokens without secrets.",
++ "permissions": [
++ "tips:overlays"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "standard",
++ "events": [],
++ "implementedBy": [
++ "POST /api/v1/overlay-tokens",
++ "GET /api/v1/overlay-tokens"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.overlay.token.revoke.json b/manifests/capabilities/tips.overlay.token.revoke.json
nnew file mode 100644
iindex 00000000..0d44a7d8
---- /dev/null
++++ b/manifests/capabilities/tips.overlay.token.revoke.json
@@@ -0,0 +1,19 @@
++{
++ "id": "tips.overlay.token.revoke",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Revoke an overlay token; open overlay streams using it are closed immediately.",
++ "permissions": [
++ "tips:overlays"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "standard",
++ "events": [],
++ "implementedBy": [
++ "POST /api/v1/overlay-tokens/:id/revoke"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.profile.get.json b/manifests/capabilities/tips.profile.get.json
nnew file mode 100644
iindex 00000000..2db984fb
---- /dev/null
++++ b/manifests/capabilities/tips.profile.get.json
@@@ -0,0 +1,19 @@
++{
++ "id": "tips.profile.get",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Read a creator's tip profile including a page that is switched off (public pages are readable without a token).",
++ "permissions": [
++ "tips:profile"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "standard",
++ "events": [],
++ "implementedBy": [
++ "GET /api/v1/profiles/:creator"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.profile.update.json b/manifests/capabilities/tips.profile.update.json
nnew file mode 100644
iindex 00000000..16e0a759
---- /dev/null
++++ b/manifests/capabilities/tips.profile.update.json
@@@ -0,0 +1,19 @@
++{
++ "id": "tips.profile.update",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Create or update a creator's tip profile on their behalf: page switch (indexing), accepting, minimums, TTS and media-request settings. Creators do this themselves with their user token.",
++ "permissions": [
++ "tips:profile"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "standard",
++ "events": [],
++ "implementedBy": [
++ "PATCH /api/v1/profiles/:creator"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.simulation.run.json b/manifests/capabilities/tips.simulation.run.json
nnew file mode 100644
iindex 00000000..4818394f
---- /dev/null
++++ b/manifests/capabilities/tips.simulation.run.json
@@@ -0,0 +1,19 @@
++{
++ "id": "tips.simulation.run",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Run the full effect path (overlay alert, goal widget, delivery) flagged test, with no Billing call, never counted in any total and never emitted as a durable event. The charter's 'tips.simulate' as a 3-segment id.",
++ "permissions": [
++ "tips:simulate"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "standard",
++ "events": [],
++ "implementedBy": [
++ "POST /api/v1/simulate"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.superchat.create.json b/manifests/capabilities/tips.superchat.create.json
nnew file mode 100644
iindex 00000000..bae194cd
---- /dev/null
++++ b/manifests/capabilities/tips.superchat.create.json
@@@ -0,0 +1,21 @@
++{
++ "id": "tips.superchat.create",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Start a paid (highlighted) chat message for a supporter; the paid_messages row exists only after Billing settles it.",
++ "permissions": [
++ "tips:checkout"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "payments",
++ "events": [
++ "tips.interaction.ready"
++ ],
++ "implementedBy": [
++ "POST /api/v1/paid-messages"
++ ]
++}
ddiff --git a/manifests/capabilities/tips.tts.request.json b/manifests/capabilities/tips.tts.request.json
nnew file mode 100644
iindex 00000000..9e2bfaca
---- /dev/null
++++ b/manifests/capabilities/tips.tts.request.json
@@@ -0,0 +1,21 @@
++{
++ "id": "tips.tts.request",
++ "version": "1.0",
++ "owner": "tips",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Start a paid text-to-speech request for a supporter, within the creator's TTS settings; delivered to chat only after settlement.",
++ "permissions": [
++ "tips:checkout"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "payments",
++ "events": [
++ "tips.interaction.ready"
++ ],
++ "implementedBy": [
++ "POST /api/v1/tts-requests"
++ ]
++}
ddiff --git a/manifests/services/live.json b/manifests/services/live.json
iindex e499a419..d4d02937 100644
---- a/manifests/services/live.json
++++ b/manifests/services/live.json
@@@ -18,7 +18,8 @@
"chat.message.send",
"live.chat_context.read",
"live.chat_effects.write",
-- "live.chat_mirror.write"
++ "live.chat_mirror.write",
++ "live.tips_delivery.write"
],
"eventsProduced": [],
"eventsConsumed": [],
ddiff --git a/manifests/services/tips.json b/manifests/services/tips.json
iindex 0b1d386b..f047c1df 100644
---- a/manifests/services/tips.json
++++ b/manifests/services/tips.json
@@@ -1,16 +1,51 @@
{
-- "version": "0.1.0",
++ "version": "0.2.0",
"contractRanges": {
-- "openvibe-contracts": "^0.1.0"
++ "openvibe-contracts": ">=0.11.0 <1.0.0"
},
"id": "tips",
"name": "OpenVibe.Tips",
-- "status": "placeholder",
++ "status": "alpha",
"repository": "OpenVibers/OpenVibe.Tips",
-- "domains": [],
-- "capabilities": [],
-- "eventsProduced": [],
-- "eventsConsumed": [],
-- "namespacesOwned": [],
-- "notes": "Creator support: tips, goals, paid messages, TTS and media requests, overlays. Charter only; no runtime."
++ "domains": [
++ "openvibe.tips"
++ ],
++ "publicOrigin": "https://openvibe.tips",
++ "health": "/api/health",
++ "ready": "/api/ready",
++ "capabilities": [
++ "tips.profile.get",
++ "tips.profile.update",
++ "tips.checkout.create",
++ "tips.superchat.create",
++ "tips.tts.request",
++ "tips.media_request.create",
++ "tips.interaction.get",
++ "tips.interaction.list",
++ "tips.interaction.record",
++ "tips.goal.create",
++ "tips.goal.update",
++ "tips.goal.close",
++ "tips.overlay.token.create",
++ "tips.overlay.token.revoke",
++ "tips.overlay.config.get",
++ "tips.overlay.config.update",
++ "tips.simulation.run"
++ ],
++ "eventsProduced": [
++ "tips.interaction.ready",
++ "tips.interaction.failed",
++ "tips.interaction.cancelled",
++ "tips.goal.updated",
++ "tips.overlay.delivered",
++ "tips.overlay.failed"
++ ],
++ "eventsConsumed": [
++ "billing.transaction.settled",
++ "billing.transaction.reversed"
++ ],
++ "namespacesOwned": [
++ "tips.*"
++ ],
++ "notes": "Creator support (roadmap Wave 9): tip interactions whose payment state mirrors OpenVibe.Billing (keyed by Billing transaction id) and whose delivery state is Tips' own; goals derived from settled interactions; paid messages, TTS and media requests created on settlement; scoped revocable overlay tokens with SSE overlays; simulation mode. Tips never moves money (ADR-012). Alpha: the placeholder on OpenVibe.Sites stays until the launch rule in README.md holds. Proposed manifest; replaces the placeholder in manifests/services/tips.json."
}
ddiff --git a/package.json b/package.json
iindex 8502b1fe..0a0110d7 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.14.0",
++ "version": "0.15.0",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"main": "index.js",
"types": "generated/typescript/index.d.ts",