Changelog
Current public contract changes and migration links
2026-08-06
- Reservation list and detail responses now share one materialized issue
snapshot and expose
issuesComputedAtplusissuesStale. A stale response keeps the prior issue set while a bounded background evaluation runs; clients should re-read until freshness advances and must not recalculate issues. - Corrected Airbnb extractor metadata so Payout is the visible ranged
capability, Reservation remains hidden but available to supported
connections, and disabled Listing, Metric, and Review capabilities remain
hidden.
GET /appsandGET /apps/{id}return only validatedfullandcursorcapabilities; storednonevalues are not client actions. - Owner statement reads now invalidate when the team's
payout_distributionaccount assignment changes. Selected manual or Ramp bank accounts remain funding accounts only and do not need that assignment; their owner distribution entries continue to use the separately assigned payout account.
2026-08-04
GET /reports/trial-balanceand/reports/trial-balance/csvnow validate every comma-separatedclassificationvalue at the request boundary. The case-insensitive supported values areasset,liability,revenue, andexpense; unsupported values return400 BAD_REQUESTwith a query issue.POST /reservations/{reservationId}/adjustmentsdocumentation now states that active bookings require eithertypeorrecurringFeeId. A selectedaccountIdalone does not classify the line; canceled bookings remain exempt from this existing rule.
2026-08-01
PUT /transactions/{transactionId}/lines/{id}now permits a reconciled deposit line to move between reservation and non-reservation items when the bank match is its only lock. The bank-record link is preserved. Source and destination saved statement periods, books closing, and an attached owner statement still reject the move; locks on unrelated lines do not.GET /teams/lookupcan now authenticate an interactive bearer user before a team is selected, withoutx-team-id. The response remains limited to teams the user can access in the selected regional partition. UseGET /teams?search=for general team-list search.
2026-07-31
- Breaking: team responses now expose the derived lifecycle state as
status; the separateeffectiveStatusfield was removed.GET /teamsandGET /teams/lookupapply the same derived semantics to thestatusfilter, and/partner/billinguses the same contract for its team rows.capabilities.activatereports whether activation can be requested, andPUT /teamreturns400 BAD_REQUESTwith structured disabled reasons when the team cannot be activated. Deactivation remains available. - Flow contact mapping creates and updates now reject unavailable contacts
with
400 BAD_REQUESTandcontext.contactIdbefore persistence. Refresh stale contact selections before retrying. POST /teamsnow rejects adefaultCurrencyabsent from the target region's supported currency catalog with400 BAD_REQUESTandcontext.defaultCurrency, before creating any team data.- The audit events API is marked work in progress: its contract is not yet frozen and can change in ways that are not backward compatible. Read audit events on demand rather than mirroring them into your own store, and contact us if you need a local copy. See Audit Events.
- Added the generated Audit Catalog: every public audit
subject with its field paths, value types, and entity-reference targets,
plus the action-code format. The
Audit Events guide now leads with reading
history directly and documents the
429rate-limit response. - Breaking: statement payment is now per owner.
POST /statements/payrequires one selection (contactId,provider,bankAccountId) per ownership member;provideris the sole ACH trigger andprovider: nullnever dispatches, even on a Ramp-backed bank account. Forprovider: "ramp"the selected bank account's Ramp account connection is the funding account; the former statement-levelprovider,bankAccountId,fundingAccountId, andselectionsfields were removed. Results now associate every payout transaction and dispatchsyncIdwith its owner contact and add arecordedstatus for book-only payments. - Breaking:
POST /statements/{id}/paywas removed. Pay a single statement throughPOST /statements/paywith one statement entry; per-statementamountcovers additional partial payments and owner receipts. - Breaking:
POST /statements/pay/previewnow accepts the per-ownerstatementsshape and returns authoritative owner allocations after rounding, default bank accounts, ACH readiness, and typed blockers. Omitpayoutsto receive server-computed defaults. GET /contactssearch now matches secondary emails on linked owner users. ContactaccessandGET /contacts/{id}/viewersresponses now includesecondaryEmails.- Audit-event collection cursors now preserve PostgreSQL's full timestamp
precision, preventing duplicate ascending pages and skipped descending rows
when a projection batch shares one timestamp. Cursors issued before this
repair return
400; restart the walk without the old cursor. - Audit-event requests with
updatedFrombefore the retained-history watermark now return the same410andearliestAvailableAtrecovery context as an expired cursor.
2026-07-30
- Breaking pre-consumer change: public audit-event collections now expose
typed entity values and
accountingImpact.netEffect. The formeraffected,changedDimensions,postingChanges, andinclude=postingChangescontracts were removed. GET /audit/events/{id}now returns revision-bound, paginatedentryChangeswith observed journal-entry identity, typed snapshots, and safe cause attribution. Continue withentryCursor; restart from page one after409 AUDIT_EVENT_REVISED.- Audit-event collections add
hasChanges,changedEntityType, andchangedPathfilters.accountIdnow matches observed before and after entry sides even when the account/currency net effect is zero. - Active team administrators can read their team's public audit events. Ordinary members, owners, and embedded sessions remain denied. Recurring fees, bank records, and account connections are now reviewed root entities.
GET /teams/resolveno longer returnsbillingCustomerId. Integrations that need the regional Hyperline customer ID must callGET /teamat the returnedapiBaseUrl.
2026-07-29
POST /accounts/{id}/banking-initnow commits account state, the opening transaction, and the feed checkpoint atomically and returns the complete opening transaction from that operation. Concurrent account cleanup can no longer turn an otherwise successful initialization into an invalid response.POST /teamsrequests sent to the generic API gateway now route an explicit bodydataRegionto the matching regional cell. The creator remains authorized throughx-team-id; omitted placement continues to use the receiving cell.- Concurrent duplicate
DELETE /transactions/{id}requests now return the standardNOT_FOUNDresponse after the winning request removes the row, instead of exposing an internal databaseno resulterror. GET /teamandGET /teams/resolvenow return effective billing-partner metadata when the selected team and partner are homed in different regions. Team application data remains regional; partner identity and lifecycle status come from the control plane.- Error
messagevalues are now static per condition across the production API. UUIDs, refs, emails, indexes, raw values, provider diagnostics, causes, and lock data are returned in structuredcontextinstead. Integrations should continue branching oncodeand readingcontext, not parsing display messages. GET /teams/issuesnow includes a stablefeatureon every issue for partner-native queue grouping. Issue state remains source-controlled: fixed conditions disappear and later recurrence reuses the issue ID with a higher version. Snooze and application navigation remain partner UI concerns.- Audit events (
GET /audit/events,GET /audit/events/{id},GET /partner/audit-events) are now the only audit surface available to external callers, and thepartner:audit:v1bundle grants exactly that family. VRPlatform's internal forensic reads —/audit/actions,/audit/actions/{id},/audit/effects,/audit/journal-deltas,/audit/mutations, and/audit/timeline— are no longer reachable with partner API keys or ordinary first-party users. They return raw change records, effect retry mechanics, and journal-row identity that the public event contract deliberately aggregates and redacts. - Audit change records now record that a sensitive field changed without storing its value. Credential, secret, token, and password fields are reduced to the changed key names.
GET /appsandGET /apps/{id}now returncategory: nullfor legacy apps that do not have a category. This aligns the response with the existing nullable app data and prevents one uncategorized app from failing the full app collection.- Reconnect-created provider syncs now change to
failedwhen their asynchronous dispatch fails instead of remaining indefinitely queued without a Trigger run. Effect retries preserve the sync and its idempotency key. - VRI-to-VRT migration is now a supported Partner API workflow under
/partner/vri-to-vrt. Bootstrap requirespartner:provisioning:v1; account and listing previews plus historical statement import requirepartner:general-ledger:v1. Requests usesourceTeamIdandtargetTeamId, and both teams must be managed by the calling partner. The former/internal/migrate-vri-to-vrtroutes have been removed. - Added partner-only
POST /team/duplicatefor asynchronous test-team copies. The source comes fromx-team-id;uniqueRefprovides deterministic exact retries; and optional anonymization preserves accounting amounts, dates, and relationships while replacing visible PII. Cloned connections are disabled and contain no credentials or sync state. Poll the returned audit action for completion; restricted keys needpartner:audit:v1for that read.
2026-07-27
- Partner API keys can use every documented public partner workflow for a selected managed team. New restricted-key bundles cover audit, calendar, files, general ledger, integrations, recurring fees, statement layouts, and team members. Destructive operations remain outside standard bundles. Credential management, self-service, internal, demo, and legacy routes stay unavailable to partner API keys.
2026-07-25
- Team responses now return
billingPartnermetadata for the same effective partner represented bybillingPartnerId: the explicit billing partner, otherwise the accounting partner, otherwise VRPlatform. GET /teamsnow acceptsexcludeTestTeams=trueto exclude the demo tenant and teams assigned to the demo accounting or billing partner while retaining VRPlatform and its direct customers.- Team responses began exposing the now-retired
effectiveStatusalongside the administrativestatus. See the 2026-07-31 breaking replacement.
2026-07-24
GET /teamandGET /teams/resolvenow return the effective non-nullablebillingPartnerId, falling back to the accounting partner and then VRPlatform when no explicit billing partner is stored. Theirpartnermetadata uses the same VRPlatform fallback when no accounting partner is stored.- Embedded
membersinGET /teamandGET /teams/resolvenow includelastNamealongside the existingfirstName, matching the member name fields returned byGET /team/members. - Added bearer-only
PUT /meso an authenticated user can synchronously update their own first and/or last name. Supplied values are trimmed, blank names and target identifiers are rejected, and the response uses the same user shape asGET /me. API keys and current read-only embedded bundles cannot call the mutation. - Plaid sandbox completion no longer treats shared test account masks as GL account duplicates when returning configuration suggestions, issues, and action capabilities. Production sessions continue to reserve last four digits across active and inactive GL accounts.
2026-07-24
- Added public audit events for synchronizing who or what changed a business
entity, which public fields changed, and what the action did to accounting.
GET /audit/eventslists upsertable events for the selected team andGET /audit/events/{id}returns one event with signed posting-bucket before and after totals. RegionalGET /partner/audit-eventsreads all managed teams in one data region. First-party access is administrator-only; partner API keys need theaudit:readscope from the newpartner:audit:v1bundle; owner users and embedded sessions are denied. - Audit events cover
account,listing,listingOwnershipPeriod,ownerStatement,reservation, andtransactionroots with event-time actor, team, and account snapshots and allowlisted field changes. For synchronization, requestorder=asc, persistnextCursor, and upsert byidwhenrevisionincreases; accounting revisions reappear on the same event ID. Ascending reads trail real time by a short visibility lag so concurrently committed revisions are never skipped. Online history is guaranteed for at least 180 days; a cursor pointing before the earliest retained event returns410withearliestAvailableAt.
2026-07-23
DELETE /accounts/{id}/connections/{accountConnectionId}now returns the detached connection ID withstatus: "deleted".- Global VRPlatform admins can now list, create, reveal, and revoke API tokens for any selected team without joining that team. Team admins retain their existing inherited access; API-key and ordinary-user callers remain denied.
- Expanded the pre-release
embed:reports:v1bundle with read access toGET /accounts,GET /listings, andGET /contactsfor embedded report filters. Their detail, CSV, and mutation routes remain unavailable to embedded sessions, and every request remains bound to the session team. - Added regional
GET /partner/listingsfor the partner dashboard Listings CSV. It returns active property-manager listings with owning-team identity, calculated display names, structured/full addresses, the existing dashboard team filters, deterministic team/listing ordering, and standard pagination. Explicit team IDs outside the authorized regional slice return403. - Added partner-only
GET /partner/connectionsfor regional connection inventory. It returns managed VRI and VRT teams, including empty teams, with active connection app metadata, error state, and current sync state. Team, company, lifecycle, app, and app-scoped error-state filters run before team totals and pagination. - Standardized sorting on
GET /bank-records,/bank-records/csv,/files,/internal/feature-flags,/partner/billing,/partner/connections,/partner/owner-statements,/partner/users,/syncs, and/teamson one signedsortparameter. An unprefixed field sorts ascending and-fieldsorts descending. Generated schemas explicitly list both variants and each endpoint's default. - This is a breaking change:
sortBy,sortDirection, and direction-suffix values are no longer accepted. MigratesortBy=date&sortDirection=desc,sortBy=-date, orsort=created_desctosort=-date. Text ordering is case-insensitive, nullable fields place nulls last, and deterministic ID tie-breakers keep pagination stable.
2026-07-21
- Added VRP-admin message-overwrite administration under
/internal/message-overwrites. The collection supports pagination, total counts, deterministic ordering, and case-insensitive partial search across patterns and replacement messages; create, replace, and delete operations reject blank fields and return not found for missing resources. - Owner statement summary list, detail, and exports now allocate manual listing payouts tagged to a non-owner payee across the ownership-period percentages. Payouts tagged directly to an owner still belong fully to that owner.
2026-07-19
POST /plaid/connectnow accepts optionalenvironment=sandbox|production. New Items default to production, and the returnedconnectIdowns the environment for completion and configuration.- PRO-16794: added team-name search, pagination, and status-count ordering to
GET /partner/owner-statements. Partner dashboards can traverse regional VRT teams withpageandlimit, oroffsetandlimit, usepagination.totalfor the complete matching count, and order bydraft,inReview, orpublishedcounts. Search is a case-insensitive partial match. - Added
GET /partner/owner-statementsfor regional partner dashboards. It returns VRT child teams with persisted owner-statement counts fordraft,inReview, andpublished; VRI and manager statements are excluded. GET /menow includes the resolved team'sdataRegionandapiBaseUrl. When the resolved team is a partner, it also includespartnerContext.managedTeamRegionswith regional API URLs and active/inactive managed-team counts.- Regional partner portfolio reads now accept
x-data-region. The header selects one storage partition without changing the authenticated partner or team context. Initial support covers team lists/lookups, team issues, and partner-user reads. - Portfolio pages and cursors remain regional. Clients that combine a multi-region portfolio call each advertised region independently.
2026-07-18
- Renamed the external banking identity resource from BankAccount to
AccountConnection. Use
/account-connections,POST /accounts/{id}/connections, andDELETE /accounts/{id}/connections/{accountConnectionId}. - BankRecord contracts now use
accountConnectionId,accountConnectionRef, andaccountConnectionfor the optional external identity.accountIdremains the canonical posting Account. - CSV bank-record imports remain valid with only
accountId; they do not need an AccountConnection. CSV exports now label the external identity asAccount Connection. - Statement payout
bankAccountIdcontinues to mean a canonical bank Account and is validated accordingly.
2026-07-17
- Added compact, source-versioned
connection.changed,sync.status.changed,reservation.changed,listing.changed,statement.status.changed, andtransaction.changedwebhook contracts. Current authenticated API reads remain the source of truth. - Webhook creation now requires an explicit verification test after the receiver stores its secret. URL/event-set changes and reactivation require a test of the current subscription revision.
- Secret rotation now emits signatures from the new and previous secrets for a 24-hour overlap. Added webhook administration quotas, 90-day terminal delivery retention, and one-minute delivery recovery.
- Outbound delivery now uses private resolve-and-pin egress. Every attempt rejects mixed or non-public DNS answers, dials one validated numeric address, preserves the original TLS hostname, and never follows redirects. Public enablement remains gated on pre-release failure drills.
- Embedded-session bearer tokens now authenticate on
GET /meand preserve their issued team binding whenx-team-idis omitted. GET /menow returnsuser.email: nullfor embedded identities, which use the partner-providedsubinstead of an email address. Email remains required for ordinary authenticated users.- Team-member reads no longer fail for users created with an empty secondary email list; stored values are constrained to JSON arrays.
- Added
onLocked=nextOpento reservation adjustment creation. It resolves books-closed and statement-period conflicts to the earliest valid concrete posting date;onLocked=errorremains the default. - Reservation adjustment dry runs now return the resolved
generalLedgerPostingAtwithout saving the adjustment. - Clarified that reservation line exclusion is set through a mapping with
accountId: null;status=excludedand lineisExcludedare derived.
2026-07-16
- Retired partner edge hosts; the public API is served only at
https://api.vrplatform.app. - Removed machine-to-machine credential references from public documentation;
public authentication is
x-api-keyandAuthorization: Beareras listed in the Authentication summary. - Documented the webhook signature headers and HMAC-SHA256 signed-string format in Webhooks.
- Documented the rate-limit policy in the Error contract:
no enforced limits currently, and the API never emits
429.
2026-07
- Added materialized, versioned
GET /teams/issuessnapshots. - Added team-owned outbound webhook subscriptions, delivery history, retries, secret rotation, testing, and replay.
- Added
team.issues.changedas the first subscribable public event. - Published generated issue and webhook catalogs from typed runtime registries.
Exact endpoint schemas are generated from current OpenAPI. Historical design context remains in repository RFCs and version logs rather than in current behavior pages.
Documentation
- 2026-07: Consolidated UI business rules, concepts, partner setup, imports, and operations into task-oriented journeys while preserving old documentation URLs with permanent redirects.
