VRPlatformVRPlatform
Build a Product UI

Statements

Build owner-statement lifecycle, layout, payout, and editing UI

Mental Model

An owner statement presents owner-side financial activity for one ownership period, month, and currency. Listing plus month is not enough: a mid-month ownership change can produce several statements.

Resources and Lifecycle

Lifecycle

StatusJournal attachmentNormal owner visibility
draftNoTeam setting can allow it
inReviewYesNo
publishedYesYes

Moving out of draft attaches eligible entries and closes owner-side activity for the period. Returning to draft removes attachment locking while preserving statement identity. Current writes use only these three statuses.

Status Transitions

Use Update statement status (PUT /statements/{id}) for every transition.

Any transition between draft, inReview, and published is allowed in both directions, subject to these enforced blockers:

TransitionBlocked when
Any status changeA later statement exists for the same ownership period
To inReview or publishedThe recomputed statement has error-severity issues
Draft or inReview to publishedA prior month in the publish window has an unfinalized statement or unattached owner activity
To draftThe caller is a scoped API credential without statements:publish; entries detach and locks lift otherwise

For scoped API credentials the statements:publish scope gates the published boundary in both directions: publishing a statement and moving a published statement back to draft or inReview both require it. Re-posting Create statement regenerates an existing statement but returns 409 if it would move a published statement away from published — status transitions always go through the update endpoint.

Publish order is enforced per ownership period and currency: finalize earlier months before publishing a later one. The status update does not check for an existing payout, so unpublishing a paid statement leaves its payout transaction in place; paying again without an explicit amount is rejected while an active payout exists.

Layouts and Visibility

Layouts define sections, columns, formulas, account groups, and owner/manager visibility. Listing mappings choose the active layout.

Read Model

Render server-calculated detail, totals, rows, source records, issues, locks, and the returned layout for the requested view. Do not recompute allocation, totals, or owner visibility in the browser.

Persisted statements freeze their effective presentation. A later layout change does not silently rewrite old statements.

Owner-summary payouts use the payout journal contact when it identifies a member of the ownership period. That owner receives the complete tagged payout. A listing payout tagged to a non-owner payee is shared across the period's owners by their ownership percentages. Transfer rows without any contact remain excluded because they do not provide safe payout attribution. For an allocated payout, use the returned drilldown as-is; it keeps the source payee contact needed to open the supporting journal activity.

Partner Portfolio Counts

Use List partner owner statements (GET /partner/owner-statements) to build a partner-level statement queue. The response contains every child team stored in VRT (storageRealm=vrtrust) in the selected regional partition, including teams with zero statements. Each team includes its identity, optional logo, creation timestamp, and persisted owner-statement counts for draft, inReview, and published. Use page and limit, or offset and limit, to traverse the response; pagination.total counts all matching VRT teams before pagination. Set sortBy to draft, inReview, or published to order by that status count, and use sortDirection for ascending or descending order. Equal counts retain deterministic team name and ID ordering. Use search to filter teams by a case-insensitive partial name match; filtering is applied before pagination.total is calculated.

The counts exclude manager statements and VRI teams. For a multi-region portfolio, call each region advertised by GET /me and retain region identity when combining the results.

Decision Table

Payouts and Description Editing

DecisionRule
IdentityOwnership period + month + currency
Owner displayRequest owner view; do not hide manager data client-side
Manager displayRequest manager view
Persist historyUse returned frozen layout/detail
Refresh layoutExplicit refresh, never automatic on read
Owner payoutPay an owner statement
Manager payoutPay manager statements
Summary payout attributionOwner contact in full; non-owner payee by ownership split
Inline descriptionRequire descriptionEdit, no descriptionLock; edit

Editability

Non-draft statements create attachment and owner-period locks. Manager-side transaction lines normally do not participate in the owner-statement period lock. Use statement IDs and lock hits, not month alone, to explain coverage.

Row descriptions can have narrower editability than the surrounding financial resource. A row backed by ambiguous source lines is not safely editable.

Preview and Preflight

Statement create, update, delete, pay, manager pay, description mutation, and historical import all take dryRun where the generated OpenAPI declares it. Layout mutations do not. Render returned validation and issues before applying an explicit layout refresh.

Mutation Recipe

  1. Load statement identity, requested view, detail, status, locks, and issues.
  2. Render returned totals and frozen layout.
  3. Determine the exact status action or narrow row edit.
  4. Dry-run the complete supported mutation.
  5. Explain new attachment or period-lock consequences.
  6. Confirm and apply.
  7. Re-read the same statement ID and view.
  8. For payouts, follow the returned transaction into its accounting month.

Failure and Recovery

If an owner-side mutation hits a persisted period, identify the locking statement and recovery action; never silently switch attribution. Return a statement to draft only through an explicit authorized workflow. For an ambiguous description row, edit the underlying source instead.

Common Recipes

Publish a statement

Load current detail, dry-run the status update, show issues and lock impact, confirm, publish, then re-read owner view.

PUT /statements/{statementId}?dryRun=true
Content-Type: application/json

{
  "status": "published"
}

Pay a published statement

Use the statement pay operation. The payout line references the paid statement, while its journal entries use payout transaction date and can appear in a later statement month.

POST /statements/{statementId}/pay?dryRun=true
Content-Type: application/json

{
  "ramp": false,
  "date": "2026-08-08",
  "bankAccountId": "66666666-6666-4666-8666-666666666666"
}

Webhook Reconciliation

statement.status.changed is emitted only when a persisted owner statement is created in or transitions among stored statuses, or is deleted. Draft projections do not emit. The body contains previous/current status and a monotonic version, but no amounts, rows, owner, payout, or template data.

API Reference

On this page