BillingVibesCharge billing.vibes-charge@1

Generated at from openvibe-contracts v0.419.0 and openvibe-sdk v0.161.0.

Version
1.0.0
Owner
billing
Visibility
public
Status
active
Compatibility
backward
Schema
https://openvibe.network/contracts/billing/vibes-charge.v1.json

billing.vibes-charge@1: one Vibes Pay charge (D12). An app creates it for a person to pay with Vibes; GET /api/v1/vibes/charges/:id answers it, and a replay of the same app reference returns the same charge. amount is a whole number of Vibes (never a fraction, never nano-USD). status moves pending -> paid -> refunded, or pending -> expired|cancelled. sandbox charges use test Vibes only, worth nothing. The paid and refunded webhook/event payloads carry the same fields plus an opaque payer_ref and no person id or email.

Fields

FieldTypeRequiredDescriptionConstraints
idstringyesULID charge id.
  • pattern ^vch_[0-9A-HJKMNP-TV-Z]{26}$
appstringyesThe app that created the charge (its app_ id).
  • pattern ^app_[0-9A-HJKMNP-TV-Z]{26}$
project_idstringyesThe app's project; paid Vibes land in that project's Vibes wallet.
  • pattern ^prj_[0-9A-HJKMNP-TV-Z]{26}$
amountintegeryesPrice in whole Vibes. A positive integer; Vibes have no fractions.
  • minimum 1
descriptionstringyesWhat the person is paying for.
  • minLength 1
  • maxLength 140
referencestringyesThe app's own reference for this charge. It is the idempotency key: a replay with the same reference returns the same charge.
  • minLength 1
  • maxLength 128
statusenumyes
  • one of "pending", "paid", "refunded", "expired", "cancelled"
pay_urlstringyesOpenVibe's pay sheet for this charge, e.g. https://openvibe.network/pay/vch_...
  • format uri
return_urlstring | nullyesWhere the browser returns after paying; null when the app gave no return URL.
  • format uri
created_atstringyes
  • format date-time
paid_atstring | nullyesWhen the Vibes moved, or null while the charge is unpaid.
  • format date-time
refunded_atstring | nullyesWhen the Vibes went back to the person, or null.
  • format date-time
expires_atstringyesThe pay sheet stops accepting payment after this instant.
  • format date-time
sandboxbooleanyesTrue for a sandbox app: sandbox Vibes only, worth nothing.

Examples

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

Valid: expired
{
  "id": "vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "app": "app_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "amount": 50,
  "description": "Sticker pack: Neon cats",
  "reference": "order_123",
  "status": "expired",
  "pay_url": "https://openvibe.network/pay/vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "return_url": "https://myapp.example/thanks",
  "created_at": "2026-11-04T12:00:00.000Z",
  "paid_at": null,
  "refunded_at": null,
  "expires_at": "2026-11-04T12:30:00.000Z",
  "sandbox": false
}
Valid: paid-sandbox
{
  "id": "vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "app": "app_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "amount": 50,
  "description": "Sticker pack: Neon cats",
  "reference": "order_123",
  "status": "paid",
  "pay_url": "https://openvibe.network/pay/vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "return_url": null,
  "created_at": "2026-11-04T12:00:00.000Z",
  "paid_at": "2026-11-04T12:01:00.000Z",
  "refunded_at": null,
  "expires_at": "2026-11-04T12:30:00.000Z",
  "sandbox": true
}
Valid: pending
{
  "id": "vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "app": "app_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "amount": 50,
  "description": "Sticker pack: Neon cats",
  "reference": "order_123",
  "status": "pending",
  "pay_url": "https://openvibe.network/pay/vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "return_url": "https://myapp.example/thanks",
  "created_at": "2026-11-04T12:00:00.000Z",
  "paid_at": null,
  "refunded_at": null,
  "expires_at": "2026-11-04T12:30:00.000Z",
  "sandbox": false
}
Valid: refunded
{
  "id": "vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "app": "app_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "amount": 50,
  "description": "Sticker pack: Neon cats",
  "reference": "order_123",
  "status": "refunded",
  "pay_url": "https://openvibe.network/pay/vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "return_url": "https://myapp.example/thanks",
  "created_at": "2026-11-04T12:00:00.000Z",
  "paid_at": "2026-11-04T12:01:00.000Z",
  "refunded_at": "2026-11-04T13:00:00.000Z",
  "expires_at": "2026-11-04T12:30:00.000Z",
  "sandbox": false
}
Rejected: bad-id
{
  "id": "vch_1",
  "app": "app_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "amount": 50,
  "description": "Sticker pack: Neon cats",
  "reference": "order_123",
  "status": "pending",
  "pay_url": "https://openvibe.network/pay/vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "return_url": "https://myapp.example/thanks",
  "created_at": "2026-11-04T12:00:00.000Z",
  "paid_at": null,
  "refunded_at": null,
  "expires_at": "2026-11-04T12:30:00.000Z",
  "sandbox": false
}
Rejected: description-too-long
{
  "id": "vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "app": "app_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "amount": 50,
  "description": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "reference": "order_123",
  "status": "pending",
  "pay_url": "https://openvibe.network/pay/vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "return_url": "https://myapp.example/thanks",
  "created_at": "2026-11-04T12:00:00.000Z",
  "paid_at": null,
  "refunded_at": null,
  "expires_at": "2026-11-04T12:30:00.000Z",
  "sandbox": false
}
Rejected: float-amount
{
  "id": "vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "app": "app_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "amount": 12.5,
  "description": "Sticker pack: Neon cats",
  "reference": "order_123",
  "status": "pending",
  "pay_url": "https://openvibe.network/pay/vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "return_url": "https://myapp.example/thanks",
  "created_at": "2026-11-04T12:00:00.000Z",
  "paid_at": null,
  "refunded_at": null,
  "expires_at": "2026-11-04T12:30:00.000Z",
  "sandbox": false
}
Rejected: person-id
{
  "id": "vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "app": "app_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "amount": 50,
  "description": "Sticker pack: Neon cats",
  "reference": "order_123",
  "status": "pending",
  "pay_url": "https://openvibe.network/pay/vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "return_url": "https://myapp.example/thanks",
  "created_at": "2026-11-04T12:00:00.000Z",
  "paid_at": null,
  "refunded_at": null,
  "expires_at": "2026-11-04T12:30:00.000Z",
  "sandbox": false,
  "user_id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ"
}
Rejected: unknown-status
{
  "id": "vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "app": "app_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "amount": 50,
  "description": "Sticker pack: Neon cats",
  "reference": "order_123",
  "status": "failed",
  "pay_url": "https://openvibe.network/pay/vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "return_url": "https://myapp.example/thanks",
  "created_at": "2026-11-04T12:00:00.000Z",
  "paid_at": null,
  "refunded_at": null,
  "expires_at": "2026-11-04T12:30:00.000Z",
  "sandbox": false
}
Rejected: zero-amount
{
  "id": "vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "app": "app_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "project_id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "amount": 0,
  "description": "Sticker pack: Neon cats",
  "reference": "order_123",
  "status": "pending",
  "pay_url": "https://openvibe.network/pay/vch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "return_url": "https://myapp.example/thanks",
  "created_at": "2026-11-04T12:00:00.000Z",
  "paid_at": null,
  "refunded_at": null,
  "expires_at": "2026-11-04T12:30:00.000Z",
  "sandbox": false
}

Validate

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