---
title: "billing.money-reason@1 · OpenVibe.Services"
canonical: "https://openvibe.services/docs/contracts/billing.money-reason"
updated: null
---

# billing.money-reason@1 · OpenVibe.Services

HTML: [billing.money-reason@1 · OpenVibe.Services](https://openvibe.services/docs/contracts/billing.money-reason)

# BillingMoneyReason `billing.money-reason@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: billing
- Visibility: public
- Status: active
- Compatibility: backward
- Schema: [`https://openvibe.network/contracts/billing/money-reason.v1.json`](/docs/contracts/billing.money-reason.json)

billing.money-reason@1: why a movement of OpenCoins, Vibes or Balance happened, in the words a person reads. \`key\` is the raw ledger reason (OpenCoins reason, or Billing's type:metadata); \`text\` is the phrase without the amount ("for the quest Publish a video"), so a page writes "+15 OpenCoins" before it; \`subject\` is the thing it was for and where to read it, when there is one. A key nobody declared reads "for something on <site>", has known: false, and is never shown as its key. Same reason kinds, one list: openvibe-contracts/lib/money-reasons.js.

## Fields

| Field | Type | Required | Description | Constraints |
| --- | --- | --- | --- | --- |
| `key` | string | yes | The ledger's own reason, kept for support and logs. A page never prints it. | - `maxLength 200` |
| `text` | string | yes | The plain phrase, without the amount: "for the quest Publish a video". | - `minLength 1`<br>- `maxLength 300` |
| `subject` | object \| null |  | What the movement was for (a quest, a stream, a tip, a creator, an app, a project, a purchase), with its own name and address. Null when the reason has no page of its own. |  |
| `site` | string |  | The site the movement belongs to, in the words a person reads (OpenVibe.Quest, OpenVibe.Live, OpenVibe). | - `maxLength 80` |
| `known` | boolean |  | False for a key no kind declares; its text says "for something on <site>". |  |

## Examples

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

 Valid: no-subject

~~~~
{
  "key": "account_merge",
  "text": "for merging your accounts",
  "subject": null,
  "site": "OpenVibe.Network",
  "known": true
}
~~~~

Valid: quest

~~~~
{
  "key": "quest:publish-a-video",
  "text": "for the quest Publish a video",
  "subject": {
    "name": "Publish a video",
    "url": "https://openvibe.quest/quests/publish-a-video"
  },
  "site": "OpenVibe.Quest",
  "known": true
}
~~~~

Valid: tip

~~~~
{
  "key": "donation",
  "text": "for a tip to @alice",
  "subject": {
    "name": "@alice",
    "url": "https://openvibe.live/@alice"
  },
  "site": "OpenVibe",
  "known": true
}
~~~~

Valid: undeclared

~~~~
{
  "key": "nobody:declared-this",
  "text": "for something on OpenVibe.Live",
  "subject": null,
  "site": "OpenVibe.Live",
  "known": false
}
~~~~

Rejected: extra-field

~~~~
{
  "key": "quest:go-live",
  "text": "for the quest Go live",
  "amount": 15
}
~~~~

Rejected: key-null

~~~~
{
  "key": null,
  "text": "for the quest Go live"
}
~~~~

Rejected: missing-text

~~~~
{
  "key": "quest:go-live"
}
~~~~

## Validate

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