Changelog
Current public contract changes and migration links
Unreleased
-
Reservation, fee, and statement
journalStatusincludes optionalreason: journalLockedwhen all outstanding changes were skipped because of accounting locks. A later calculation timestamp does not clear unapplied work. -
Fees and statements with no known journal changes now report
currentinstead of a falsestalestatus. Actual pending work and locked-history failures remain visible. -
Exhausted database socket connection attempts return
503 SERVICE_UNAVAILABLEinstead of a generic500. Writes still require outcome reconciliation before retrying. -
Transaction reads explain why Cancel is unavailable for a failed or canceled ACH request. These terminal requests no longer show a waiting-for-reconciliation reason. Available payment and archive actions are unchanged.
-
MCP
/directorysupports reviewed accounting reads and confirmed record creation, updates, and deletion, including payment bookkeeping and owner statement preparation. It rejects provider payment execution, credential changes, unreviewed routes, and input switches. The custom/endpoint retains full API access. See MCP setup. -
Path, query, and body validation failures use the documented public error envelope. Pagination rejects fractional and unsafe numeric values before SQL.
-
Journal refreshes detect changed sources and postings before applying their changes. Book closing coordinates with writes already in progress.
-
Bank-balance recalculation corrects balances before the first checkpoint and processes large update sets in bounded, atomic batches. Existing stored balances change when recalculated; this release does not perform a backfill.
-
The TypeScript client now attempts writes once, including when
attemptsis greater than one. Automatic retries remain available forGET,HEAD, andOPTIONS; there is no write-retry opt-in. Reconcile writes with an uncertain outcome before sending another request. Custom response assertions still run on writes unless explicitly disabled withassertOnLastAttempt: false. -
Both
throwIfErrorforms preserve public error codes and recovery fields. Malformed or missing error envelopes throwApiClientResponseErrorwith the HTTP status. Error context is typed asunknownand requires narrowing. See Errors & Retries.
2026-09-05
- Offline
POST /transactions/{id}/paysupports expenses whose terminal Ramp bills were permanently archived, including after expense unarchive. It retains payment history and accounting locks. Terminal Unpaid resets also accept the UI's explicit null payment date and bank account. - Deposit updates containing only
lines_updatepreserve unrelated source lines and journal postings. Invoice matching no longer fails because an untouched legacy fee line would otherwise change party during a full deposit refresh. Accounting locks still protect the selected lines and their resulting postings.
2026-09-04
PUT /syncs/{id}acceptsqueued,started,completed, orfailedasstatus. Cancellation requiresPOST /syncs/{id}/cancel.- Manual
POST /transactions/{id}/paynow reads its selected GL bank account fromfundingAccountId, matching the existing client payload. The temporaryaccountIdfield is removed. - Failed Ramp expense dispatches automatically return the expense to Unpaid and refresh its journal payment entries. The failed attempt remains in provider history and Pay becomes available for retry.
- Ramp expense Cancel now holds the existing bill, deschedules its payment, and returns the expense to Unpaid. A later Pay releases and reschedules the same bill. Archive remains the separate permanent bill action.
- Owner CSV imports now create or update standalone owners when a row has no
listing.
Company Typecan determine individual or company kind, and a sourceTypecolumn cannot change the contact type from owner. - CSV resource metadata now publishes the versioned detection aliases, value maps, mapping and row requirements, fixed values, and import effects used by generic processors. Expense and deposit detection infers date format and leaves ambiguous slash dates for explicit mapping.
2026-09-03
- Public audit events now include event-time actor organization,
attemptedEntityChanges, finite lock evidence, supported recovery actions, and theembeddedsource. Blocked reservation events show only reviewed attempted fields; committed changes remain separate. - Audit collections add inclusive
occurredFromandoccurredTofilters. Contact create, update, archive, restore, delete, batch, and import activity now uses the reviewed contact field catalog. Owner-statement attachment evidence stays in the statement event that caused it. - Selected-team audit reads now use
audit:read. Team Admin and the additive Audit Log bundle grant it; Standard Member does not. Signed-in partner members can use the regional partner collection within their stored all, assigned, and direct team reach. - Added subscribable
audit.event.changedinvalidations for each new public event revision. The payload identifies the event, revision, and current detail endpoint and follows existing self and managed-team subscription scope. - Embedded sessions can receive
embed:banking:v1for the three-step Plaid connect workflow. PMS reservation and contact imports use their Connection as sync actor, identical reservation imports no longer emit activity, and request IDs are no longer derived from session or correlation headers. GET /api-tokens/permission-bundlesnow exposes every assignable API-token bundle with its stable name, display title and description, and expanded permissions. Token-management clients no longer need a hardcoded catalog.- Audit action, effect, mutation, and timeline reads now retain the stored actor name and email after the user is deleted. The actor ID was already retained.
- Partner API keys can now queue deletion of a directly managed team through
DELETE /team?confirm=true. Restricted keys requirepartner:team-deletion:v1; partner deletion cannot useforce=true, and the returned operation remains readable from the partner team after deletion. - Failed
POST /teamsrequests no longer leave discoverable global-only teams. Slugs are checked in the global registry and target region, incomplete teams remain hidden, and an interrupted create can be retried safely. - Failed CSV imports now return
csvParsingFailedfor file and header errors orcsvImportRecordFailedfor invalid data rows instead of the genericoperationFailedresult. POST /teamsnow rejects a Hostaway-managed property-manager team unlessdataRegionishostaway. Operating country can still determine currency and tax defaults, but it cannot place a Hostaway client in another region.- Expense Pay requests now post accounts payable against the selected Ramp
funding account before dispatch. Manual Mark as paid accepts the selected GL
bank
accountIdand uses it for the payment journal. - Canceled Ramp expense payments keep their existing bill, return the expense to Unpaid after confirmation, and allow another payment attempt on that bill. Payout retry behavior is unchanged.
- ACH setup rejects routing numbers with an invalid ABA checksum. Failed setup reads preserve Ramp's bank-detail rejection instead of replacing it with an unrelated Vendor-owner instruction.
- Missing or stale Ramp funding selections return the actionable validation
message
Select an available Ramp funding accountand are not reported as unexpected server failures. - Journal-relevant recurring fee updates now return one
reservation-journal-refreshoperation. Reservation, recurring fee, and owner statement reads exposejournalStatusplus the same operation while recalculation is in progress. Operation detail accepts typedact_andop_identifiers, and existing UUID operation identifiers remain valid.GET /operationsacceptsinitiatedBy=me, and operation responses identify a user or system initiator. Authenticated owners can poll embedded journal refresh operations that affect reservations in their owner access. Statement finalization, payout preview, and payout reject non-current journal scopes withJOURNAL_RECALCULATION_PENDINGafter the tenant guard is enabled. - VRI historical statement import now consolidates same-date source statements when re-listed properties map to one target listing. All derived balances and eligible lines are retained in the single target statement.
- VRI historical listing previews now separate statements owned by a listing
from statements that only reference one of its reservations. Use
importedStatementCountfor owned statements andreferencedStatementCountfor all mapping references.
2026-09-02
- Historical statement imports now classify
lineitems that reference the team'spayout_distributionaccount as signed transfers. Statement details, summaries, and stored financials therefore agree on payouts and expenses. - VRI-to-VRT preview preparation and activation now emit one durable API-owned lifecycle event per pair. The authoritative migration observer owns the verified event through the same shared tracking contract and transport.
GET /booking-channelsnow accepts eitherintegrations:readorrecurring-fees:read. Operations and recurring-fee API keys can load fee-referenced channel data without receiving broader integration access.- Breaking before permission launch: Operations now receives
calendar:readwithoutcalendar:writeorcalendar:delete. Operations users can view calendar blocks, while create, edit, and delete controls and API mutations are denied. - Read Only team members can now resolve the selected team before opening connection details, Team General, Owner Portal settings, Owner Statements settings, and Opening Balances. The role gains no write permission.
- Owner CSV resource metadata now orders identity and contact fields before reference and listing fields. First name, last name, company name, and company type are marked required; owner kind and listing are optional.
2026-09-01
- App connect and reconnect requests that exhaust the 25-second provider wait
now return
504 GATEWAY_TIMEOUTwith the connection-specific static message. The provider run may continue after the request stops waiting. The export-renderer message remains limited to export tasks. - Reservation adjustment creates without an explicit posting date now move a
locked natural date to the first open period by default. Pass
onLocked=errorto retain rejection. Reservation detail now marks inactive adjustment entries as statement-period locked when deletion would rewrite protected history. - Replacement payouts now receive their own
PAY-YYYYMM-XXXXXreference when the create request omitsuniqueRef. Ramp dispatch rejects payouts without a stored reference before provider work is queued, and transaction reads report Pay as unavailable. - Authenticated owners can now read an ACH verification operation when its primary contact target is in their server-derived owner access. Other contacts and operation types return an opaque not-found response.
- Contact payout
providerPaymentnow includes the masked destination account suffix captured for that attempt and its requested arrival date. Historical attempts remain unchanged after ACH account updates; legacy attempts without a reliable snapshot returndestinationAccountLast4: null.
2026-08-31
- Added
POST /transactions/{id}/payment-returnsfor full and partial external owner-payout returns. It creates a linked compensation, supports dry run and exact BankRecord reconciliation, and leaves the original payout active. - Transaction reads now expose return links, effective time, cumulative return status, remaining amount, compensation IDs, and direct replacement ID.
- Added atomic
POST /bank-records/actions/batchfor dry-run or apply of unmatch, exclude, and reactivate across at most 500 distinct records. - Exact-file CSV confirmation now blocks completed duplicate imports with
csvExactFileDuplicateunless the caller sends the explicit intentional-reimport override. - Ramp provider-payment Archive now leaves Returned payout accounting active. Failed and Canceled payments keep the existing accounting archive behavior.
- The banking guides now explain how published ledger templates can provide ordinary Bank Fees and Interest Income accounts. A team can use a BankRule as its repeatable interest mapping; there is no global beneficiary default.
- The banking and transaction guides now document the existing channel-held security-deposit flow, open-period release and forfeiture adjustments, and the existing base-reservation refund and manual-adjustment flow. They also reserve exclusion for non-cash rows and describe the existing transfer behavior: one Transaction with one bank-record match on each bank-account side.
- Breaking before release: bank-record reads no longer accept
includeMatchingTransactionsor returnmatchingTransactions[]. Request exact proposals withincludeMatchingTransaction=true, set the optionalmatchingTransactionDaysOffset, and read every proposal frommatchingTransactionSets[]. - Projection-backed statement and owner-summary reads now return a freshly computed result when only the derived-cache write exhausts a database connection. Stale projections remain unusable, the persistence failure stays visible in monitoring, and other database failures retain their existing response behavior.
2026-08-30
POST /connections/{id}/connectnow derives the app from the existing team-owned connection whenappIdand signed callback state are omitted. UnscopedPOST /connections/connectrequests still require one of them.- High-volume team deletion now commits bounded table and journal batches and checkpoints each regional cleanup group. Retries resume from the last committed group, while the internal job status exposes that progress. The deletion task and stale-job lease now support a 12-hour safety window.
2026-08-29
- Account deletion now recognizes BankRule selectors and posting lines plus
recurring-fee formula inputs as dependencies. BankRule and inactive-fee
references can use
onLocked=archive; every account used by an active fee remains protected from both deletion and archive. - Reservation journal refreshes now propagate database deadlocks and lock timeouts to their transaction owner so a failed transaction is not treated as a successful partial refresh.
- Ramp ACH setup now returns
RAMP_VENDOR_OWNER_REQUIREDwith the connection setting destination when configuration is missing. Existing ownerless Ramp vendors return manual remediation in their failed ACH state. Failed payment requests that never created a Ramp bill archive accounting locally, while an existing payout is booked to the selected Ramp funding account before its first provider attempt. - Breaking before release: public HTTP and batch errors now use one finite
uppercase code registry. Regional misroutes return an exact
MISDIRECTED_REQUESTcontract, migration freezes exposeteamId, and unknown failures use static messages. - Breaking before release: connection prompts remain HTTP 200 with the finite
lower-camel-case codes
extensionRequired,formRequired,linkRequired, andoauthRequired. Provider failures now return502 BAD_GATEWAY; the 25-second awaited limit returns504 GATEWAY_TIMEOUT. The former HTTP 200errorresponse is removed. - Operation, CSV-import, and team issue schemas now publish finite code sets. Batch item repository aliases are mapped to their public HTTP equivalents.
- Breaking before release: CSV preview and import failures now use typed
camel-case recovery codes. The generic
csvImportFailedandoperation_failedvalues are replaced by phase-specific codes andoperationFailed. Row issue codes are now a closed CSV-owned enum; resource validation failures retain their original issue in structured details. The API validates every reviewed plan chunk before resource writes and exposes import outcomes only after their manifest is finalized. - Shared full-date range filters now normalize the documented legacy comma
separator before route execution. Account reconciliation summaries therefore
accept both
start...endandstart,endwithout passing a combined value to database date serialization. - Re-inviting a team member now returns
409 CONFLICTif the membership changes during invitation preparation. Same-role re-invites continue to preserve the existing identity and explicit permission bundles.
2026-08-28
- Breaking before release: the forwarding gateway now requires
POST /teamsGeneral Ledger requests to provide an explicitdataRegionofus,eu,ap, orhostaway. A strict regional worker may omit the region to use its own cell and returns421 MISDIRECTED_REQUESTfor an explicit mismatch. Crunchy GL placement returns400 BAD_REQUESTbefore provisioning. Because General Ledger is the default, these rules also apply whengeneralLedgeris omitted. Non-General Ledger teams remain restricted to Crunchy, and an explicitly selected non-Crunchy region now returns400 BAD_REQUESTbefore provisioning. Their omitted region defaults to Crunchy; direct regional workers return421 MISDIRECTED_REQUESTwith that placement. GET /statements/pdfnow renders one owner statement PDF directly and returns its signed URL without creating an operation. The queuedPOST /statements/pdfremains available.- All 32 generated artifact paths now expose the same delivery split. GET
awaits admitted work and returns
{ url, expiresAt }; POST queues a durable export and returns the standard operation acknowledgement. Oversized GET requests returnEXPORT_REQUIRES_POST. - CSV, range, batch, PDF, and ZIP renderers run in Trigger and upload directly to regional storage. The public request Worker materializes only one explicitly selected statement PDF, and durable exports no longer invoke a public GET or copy through a transient artifact.
GET /statements/by-period/csvnow waits for its single-statement Trigger renderer to upload directly into regional transit storage, then returns only the signed URL metadata.- Trust Reconciliation PDF GETs now wait for rendering outside the regional Worker and return signed transit URLs. Matching POST routes create durable export operations, avoiding large report data and PDF buffers in Worker memory.
- Temporary export links now expose an absolute
expiresAtmatching their seven-day lifetime. R2 CSV and download metadata is aligned across temporary and durable artifacts. - Queued export configuration failures now retry within a fixed limit and
become terminal failed operations instead of remaining
running. - Completed export operation resources now include a stable authenticated file download URL. Reservation and transaction journal refreshes both run inline for one explicit ID and queue for multiple IDs or an omitted selection.
- Webhook test and replay responses now nest the standard operation acknowledgement instead of merging its fields into the delivery response.
2026-08-27
- Trust Reconciliation JSON, CSV, and PDF requests now validate
listingIdas a comma-separated list of listing UUIDs. Malformed values return400 BAD_REQUESTbefore report work starts. - CSV upload, inspection, preview, confirmation, and import failures now expose
stable recovery reasons in OpenAPI. Validation details are returned in
issues; asynchronous source failures retain their specific failure code. Expired results use410 GONE, and oversized requests use413 PAYLOAD_TOO_LARGE. Preview and import status now use the shared operation lifecycle and failure object, and acknowledgements no longer expose the internal CSV Connection. - Internal operators can prepare one disconnected VRT preview with
POST /internal/teams/{teamId}/vri-vrt-preview, selecting the source users who receive access. Activation usesPOST /internal/teams/{teamId}/vri-vrt-preview/activate?confirm=trueand preserves preview configuration while moving each PMS credential to its distinct target shell. Repeating activation repairs missing lifecycle effects without moving credentials twice. GET /menow identifies prepared VRI-to-VRT preview relationships for the selected source or target team, including the snapshot timestamp and preview lifecycle. After activation, the selected source user receives the active target link while the target no longer presents itself as a preview.- When test or demo teams move between Hyperline Development and billing through VRPlatform or Ximplifi in Hyperline Production, the previous environment is now cleaned up before the target subscription is created. Moving to an external billing partner cancels the subscription but retains the customer for a later return; VRPlatform-to-Ximplifi changes also retain the Production customer.
- Forced team deletion now removes statement-period-locked journal data and processes at most five team deletions concurrently. It also locks the target team and accounts before child cleanup, commits that cleanup, and performs a final connection pass in the locked transaction that removes the team. Tenant-owned connections now also cascade with team deletion, so a remaining connection cannot block the confirmed removal. Reservation mapping rows likewise cascade with an account that has already passed deletion safety checks. The active-subscription safeguard remains enforced.
- Effective permissions and permission bundles returned by
GET /me,GET /team/members, andGET /partner/membersare now enum-backed in the OpenAPI contract. Generated API client consumers receive literal unions and the exportedApiScopeandUiPermissionBundleNametypes instead of untyped strings.
2026-08-26
- Completing team onboarding no longer initializes or changes subscription status, billing plan, or cancellation date. Missing billing state remains visible until the Hyperline workflow reconciles it.
- Breaking before release: the Stripe payout reconciliation CSV preset now
requires only the payout bank account. Reported categories and fees resolve
through
stripe_<name>transaction line mappings; configured application IDs, fee rates, fixed fees, and category account IDs were removed. GET /reservationsandGET /reservations/csvnow acceptdateField=cancelledAt. The existing single-date and inclusivestart...endsyntax filters on the reservation cancellation timestamp and composes with other reservation filters.- Listing-parent dry runs and mutations now return the structured
lockedAccountingDataandlistingGroupHistoryMigrationcontext when a zero-value owner revenue or expense row predates the parent statement's open date. The blocked operation still leaves listing, ownership, statement, and journal state unchanged. - Explicit
POST /reservations/journal-entriesID selections now finish inline and atomically.totalcounts completed refreshes; a missing, locked, or failed reservation returns structured per-ID details and rolls back the selected set. Omittingidsretains queued portfolio refresh behavior. - Transaction create and batch-item requests now reject a missing description before execution for every non-transfer type. Transfers may still use the server-generated bank-context description.
POST /statementsnow returns409 CONFLICTwith structured identity details when another statement already occupies the requested listing and effective start date. Reload current statements instead of retrying the create as a transient server failure.- Breaking before permission launch: the dashboard role catalog now contains Team Admin, Standard Member, Operations, and Read Only. Accountant, Owner Statements, and Reports Viewer were removed; stored shadow assignments are migrated to their replacements.
- Replaced broad transaction writes with independent expense, deposit,
transfer, and payout write scopes. Operations receives only
transactions:expenses:write; broad roles receive all four. Type changes require both scopes, mixed batches are checked before mutation, and payment state still needs the separate payment permission. - Operations can now read calendar blocks, recurring fees, and statement layouts and can create or edit expenses. It still has no calendar mutation, report, bank, reconciliation, non-expense write, transaction delete, or payout access.
- Read Only now includes matching exports for listings, contacts, reservations, transactions, accounts, statements, reports, and bank records.
- Standard Member no longer includes owner or vendor ACH setup. Team Admin includes ACH setup, while ACH execution remains an additive ACH Payer grant.
2026-08-25
- Ramp payout Cancel and Archive now return the standard asynchronous
operationIdcontract. PollGET /operations/{id}for theprovider-payment-recoverylifecycle, then refresh the transaction and provider-payment history for the canonical outcome. The status read requiresoperations:read; it no longer requires access to integration sync details. - Ramp payout recovery cancellation normalizes to the public terminal
failedstate. Provider-specific cancellation details remain internal. - Banking documentation now starts with a short workflow index. Use Reconcile Bank Records for transaction and BankRule suggestions, explanations, ambiguity, automatic execution, and multi-booking payouts. Use Bank Accounts and Connections for Plaid, feed mapping, imports, ACH readiness, and recovery.
2026-08-24
- Audit Events now cover major team and access settings, accounting rules and mappings, recurring configuration, integration mappings, API tokens, webhooks, and templates. Protected values appear only as redacted field names. Coverage is forward-only and does not backfill earlier changes.
- Breaking: Ramp payouts can be submitted only once. Provider payment history cannot be unlinked, and Failed, Returned, or Canceled payouts must be archived before creating a replacement payout. Vendor-expense retry behavior is unchanged.
- Transaction reads now include
providerPaymentActionswith server-owned availability and disabled reasons. Added provider-first Ramp payout Cancel and Archive operations plus explicitrecreatedFromTransactionIdlinks. - Ramp payout fields and hard delete stay locked after every ACH attempt.
Same-bill retries made directly in Ramp remain in attempt history, and
Returned now requires Transfer API
RETURNED_BY_RDFIevidence. - Bank-record transaction suggestions now include typed match reasons,
matchingDate, ambiguity, and related listing and reservation context. Bank-rule suggestions include direction, account-scope, and per-condition outcomes so clients can explain why each suggestion exists. - Bank-record reads now accept
includeMatchingTransactionand a separatematchingTransactionDaysOffsetthat defaults to seven days. The orderedmatchingTransactionSets[]items contain one to five eligible transactions. Bank-rule suggestions remain separate inmatchingRules[]; multi-member discovery uses an internal seven-day maximum, considers at most 20 eligible nearby candidates, and returns at most 10 sets. The overloadedincludeMatchingTransactionsquery remains supported but is deprecated. - Rules remain ordered deterministically, but same-mode rules with the same
priority are marked ambiguous. If multiple automatic rules share the highest
matching priority during bank-record ingest, the record remains unmatched
and the batch returns a
CONFLICTissue withcontext.bankRuleIds. - Reconciliation suggestions still require an exact total. This change does not add amount tolerances, adjustments, or multi-bank-record matching.
- The CSV workflow guide is now named Import Data from CSV.
- Breaking before release: normalized the CSV import contract. Preview
requests now use
selection, operation responses are bare objects, lifecycle status usesstartedandcanceled, leaf paths use{id}, and import status and records use/csv-imports/{id}. - CSV upload references now retain their resource. Clients send
resourceonly toPOST /csv-imports/uploads; upload, inspection, and preview requests do not resend it. - CSV record pages now accept up to 250 records and use the shared opaque cursor contract. Preview confirmation no longer accepts a JSON body.
GET /teams?excludeTestTeams=truenow excludes teams explicitly marked for testing in addition to the demo tenant and its accounting or billing teams.- Partial
PUT /recurring-fees/{id}requests now preserve an existing percentage rate type whenrateTypeis omitted. New fee definitions still default an omitted rate type to Flat Rate. - Bank-rule create and preview requests now return validation errors when an expense omits its vendor or a deposit supplies expense-only fields.
- Ownership-period create and update requests now reject a repeated owner contact during request validation.
POST /team/members/invitenow returns the documented400 BAD_REQUESTconflict when the selected team already contains an owner membership for the email. The request creates no invite token and sends no email.
2026-08-22
- Management Commission tax now posts separately for included or excluded tax behavior when the tax rate has a payable account. If its optional debit tax override is omitted, the fee's debit account is used for that side.
PUT /listings/{id}/opening-balancecan clear one existing listing opening balance to zero across a statement-period boundary. Non-zero changes, books closing, and journal entries directly attached to an owner statement remain locked.- Added public
GET /countriesandGET /countries/{countryCode}endpoints for pre-provisioning country selection. Responses include the English name, two-letter country code, applicable currencies, and assignedus,eu, orapdata region.
2026-08-21
- Added
GET /partner/teams, a control-plane team catalog that lists the authenticated Partner's managed teams across all data regions. vrt_team_lookupnow searches globally throughGET /me/teamsfor OAuth orGET /partner/teamsfor Partner API tokens. Callers no longer select a regional partition before finding a team.- Deprecated
GET /teams/lookup. UseGET /teams?search=for rich regional inventory,/me/teamsfor OAuth discovery, or/partner/teamsfor Partner API token discovery.
2026-08-20
- Breaking: the Connection-scoped CSV import API now supports fixed templates
only. Its reviewed upload, preview, confirmation, and asynchronous status
routes were removed; reviewed imports use the top-level
/csv-importsworkflow.
2026-08-19
- Ramp owner ACH setup now treats contact address and phone as optional. New vendors use the connected Ramp business location when needed and no longer inherit another vendor's owner or location. Structured Ramp vendor validation failures are returned as the setup failure reason when available.
- Contact ACH payment methods now include nullable
failureReasondetail for failed setup attempts. The value comes from safe sync/change status and never exposes raw provider bank-response bodies. POST /transactions/{id}/provider-payments/{providerPaymentId}/cancelrequests Ramp cancellation for a materialized payment that has not initiated. Ramp remains authoritative, while the VRT payout accounting and payment link remain intact.- Email team-member invitations now reuse their prepared identity and link after authorization commits instead of repeating identity and membership preparation. Delivery failures and copy-link behavior are unchanged.
- Ramp
providerPaymentresponses now include provider status detail, payment method and reference, the submitted arrival target, and Ramp-returned scheduled-initiation, initiated, and completed timestamps. Ramp payment events are refreshed from the current bill and cannot regress a processing attempt back to requested. - New and existing teams now deny partner-derived
ach-payments:executeby default. Existing denial policies are preserved, direct memberships remain unaffected, and an authorized direct manager can explicitly remove the ACH denial for a team. - Guest Balances now retains the positive accounts-receivable reversal from a zero-dollar co-host clearing transaction. The reversal can offset the reservation's earlier payment, so fully cleared reservations no longer appear as payment-only credits.
- Authenticated team-scoped writes return HTTP
423with codeTEAM_MIGRATION_FROZENwhile a controlled regional migration is copying and verifying that team's data. Reads remain available; clients should refresh team discovery after the freeze to obtain the new regional API base URL. - Schema-less DELETE endpoints accept an empty body even when a client sends
Content-Type: application/json. DELETE endpoints that declare a body keep validating their JSON schema. - Targeted reservation fee, adjustment, and A/R journal refreshes now return
the same structured
journalEntrieslock as full refreshes when applying only unlocked changes would split an otherwise balanced journal group. - PMS line-mapping initialization now proves multi-team line-type usage with bounded indexed lookups instead of scanning every matching reservation line.
2026-08-18
POST /statements/pay/previewnow returns awarningsarray. An explicit positive amount above the statement's remaining available balance adds the non-blockingamountExceedsAvailableBalancewarning with structuredavailableBalanceandexcessAmount; overpayment remains allowed.POST /teamsacceptsmigratedFromTenantIdto atomically link a newly created GL team to the non-GL VRI team it replaces. The source must be managed by the same partner; invalid links are rejected before team creation.- Historical statement lines can now link an existing reservation with
matchReservationConfirmationCode. Matching is scoped to the statement listing; unknown, ambiguous, or conflicting references are rejected before import. - Guest Balances
datefilters now accept a single date or shared date-range syntax. A range uses its inclusive end as the report's as-of date; malformed ranges return HTTP 400 before report queries run.
2026-08-17
- Long-running routes now return
{ operationId, type, status: "queued", resource }.GET /operationsadds requester-scoped history, filters, retained status counts, and cursor pagination. - Supported resource reads include retained operation counts plus actionable queued, running, and latest unresolved failed work. Team lists retain this state across refresh without per-row operation requests.
- Calendar updates, connection sync and extract, CSV preview/import, payment dispatch, migration, journal batches, recurring runs, and other long work now use the same four-state operation lifecycle.
- Generated CSV, PDF, and ZIP routes now have
POSTinitiation and a durable file result. Existing generatingGETroutes are deprecated compatibility endpoints. Download routes remain synchronous. - CSV preview and import status now read persisted VRPlatform results instead of Trigger.dev. Public operation responses never expose runtime IDs, effects, attempts, child progress, or provider details.
- Team deletion now retains its audit action through destructive cleanup, so authorized deletion runs can persist their final mutation and follow-up work after the selected team row is gone.
- Bank-record list and CSV-export filters now validate every UUID in
ids,accountId, andaccountConnectionId. Malformed values return HTTP 400 instead of a database error. - Calendar block and unblock failures no longer expose or classify
PMS-specific messages in the API. Integrations map recognized denials to the
stable
calendarRequestRejectedreason; unknown failures remain server errors and are reported by the integration runtime.
2026-08-16
-
Asynchronous operation status is now read from the top-level
GET /operations/{id}endpoint. The short-lived/partner/operations/{id}path was removed before wider adoption. -
Operation responses now include a stable public
type. Reads remain scoped to the tenant that initiated the operation, not a target entity named in the request, and internal payloads, errors, effects, and runtime ids remain private. -
Team deletion acknowledgments now return
operationIdandstatus=queued. The same operation resource reports the provider-neutralteam-deletetype; Trigger run IDs and destructive-job diagnostics remain internal. -
Concurrent removal, demotion, or permission replacement can no longer remove every direct access manager from a team after UI Permission Roles is enabled.
-
Re-inviting an existing member with the same legacy role now preserves all assigned dashboard roles. Requesting a different role replaces the complete assignment with that role's compatibility defaults before retryable email delivery begins. A delivery error does not roll back that committed change.
-
UI Permission Roles and Operations Accounting feature changes now invalidate every affected authorization cache, including feature deletion.
-
Authorization mutations now clear affected cached access before returning, and delayed membership projection events cannot restore an older role or dashboard-role assignment after a newer revision was applied.
-
Mutations that use the asynchronous operation contract return
{ operationId, type, status: "queued", resource }. PollGET /operations/{id}for the provider-neutraltype, queued/running/completed/failed status, and lifecycle timestamps. Reads are scoped to the tenant that initiated the operation; payloads, errors, effects, and runtime ids remain private. See Asynchronous operations. -
Concurrent removal, demotion, or permission replacement can no longer remove every direct access manager from a team after UI Permission Roles is enabled.
-
Re-inviting an existing member with the same legacy role now preserves all assigned dashboard roles. Requesting a different role replaces the complete assignment with that role's compatibility defaults before retryable email delivery begins. A delivery error does not roll back that committed change.
-
UI Permission Roles and Operations Accounting feature changes now invalidate every affected authorization cache, including feature deletion.
-
Authorization mutations now clear affected cached access before returning, and delayed membership projection events cannot restore an older role or dashboard-role assignment after a newer revision was applied.
2026-08-15
- VRI-to-VRT historical statements now select ownership periods only from the statement's mapped target listing. Reservations referenced by a statement can remain on another mapped listing without redirecting statement ownership.
- Historical account previews now collapse lines onto their preserved structured account paths. Optional description rules are restricted to broad paths, and reservation reuse checks PostgreSQL's real deduplication identity before inserting rows.
2026-08-14
-
Current early-access Partner bundles now grant their complete domain workflows, including deletes, exports, journal posting, statement lifecycle, account and tax-rate maintenance, bank cleanup, team configuration, and partner-member management. Existing managed keys derive the expanded scopes from their bundles without replacement. Payment recording, ACH execution, credential administration, and team partner-deny policy remain separate.
-
partner:general-ledger:v1now grantsbooks:closeforPUT /team/books-closing. Managed Partner-token authorization derives effective scopes from its bundles, so existing keys with this bundle gain the capability without replacement. -
VRI-to-VRT historical import reruns now preserve imported reservations that are referenced by live journal entries and update their corrected listing mapping in place. Existing payout and deposit links remain attached.
-
UI Permission Roles can now be enabled by team and canaried by user. Until enabled, interactive users keep legacy authorization while migrations and every membership writer maintain the new role-bundle data in parallel.
-
Existing and newly created legacy
usermemberships receive Accountant. Team Admin, Partner Admin, and ACH Payer remain separate additive roles; Standard Member is available only as an explicit new assignment. -
Bundle and partner-policy mutations return
403for legacy-mode actors. Last-access-manager protection is enabled with bundle authorization and a flag rollback restores the earlier member-management behavior. -
Team partner-deny policy affects partner API keys and embedded sessions only after full-team enablement. Partial user canaries do not change integration access.
-
Ownership-period journal attribution retries now finish without changing journals when their target period was deleted after the original mutation. Current ownership and all journal locks remain authoritative.
-
VRI-to-VRT historical listing previews now include listings used by reservations referenced on importable statements. Imports resolve those targets before writing and return a user error for any missing target instead of a database foreign-key failure.
-
Recurring-fee reservation refreshes now update list-level manager, owner, tax, and payment totals in the same transaction as the fee journal. List and detail totals remain aligned when a fee formula includes deductions such as channel commissions.
2026-08-13
- Reservation detail, list, filters, and owner-statement payment projections now keep the full guest charge when co-host A/R activity meets or exceeds it. Excess payment remains an overpaid credit instead of being compared with only manager revenue; partial co-host payouts retain manager-only collectibility.
POST /transactions/batchnow reuses an existing transaction when itssourceIdmatches, even if the submitteduniqueRefchanged. Duplicate or concurrentsourceIdsubmissions return an item-level issue instead of a raw database constraint error.- Posting-dated recurring-fee adjustments now preserve a dependent fee's complete historical group when any row is attached to an owner statement. The new adjustment still posts its balanced open-period correction; fully editable dependent fees continue to recalculate transitively.
POST /account-connections/batchnow returns item-level issues for conflicting create or update groups without leaving the request transaction unusable. The failed group is fully rolled back and later batch processing can continue; no partial group is persisted.POSTandDELETE /calendar-blocksnow return a 400 user rejection when the provider says that a property is muted. Superseded on August 17 by the provider-neutral integration-owned classification above.- Guest Balances now preserves the A/R relief leg of a zero-dollar co-host reclassification when the reservation charge is on accounts receivable. Paid channel-collect reservations no longer appear with their full charge and zero payments; zero-charge phantom co-host credits remain excluded.
2026-08-12
- Default General Ledger initialization now selects a published template by managing partner rather than data region. Teams inherit the VRPlatform global template only when their partner has no template. Existing but unpublished partner templates fail setup instead of silently inheriting global settings.
- Centrally managed reservation-line defaults use the same partner or global scope as the selected General Ledger template. Existing team-owned mappings and exclusions remain unchanged.
- An explicit mutation of an independently balanced reservation adjustment can now refresh its targeted journal group while the parent reservation remains GL-inactive. Reservation status changes continue to inactivate the complete reservation journal.
- Owner statement layout
otherSectionsnow keep reservation adjustments with different source line IDs as separate rows. Each row retains its own description, account category, and amount; net-revenue reservation aggregation is unchanged. - Guest Balances now excludes reservation-scoped zero-dollar co-host reclassifications when the reservation charge is outside accounts receivable. An A/R leg paired with an equal Co-Host Payouts offset no longer appears as a guest payment or creates a phantom credit balance.
- Posting-dated reservation adjustments now preserve statement-attached historical recurring-fee rows. The adjustment and its line-linked fee effect post on the selected open date without normalizing older fee rounding; recurring-fee adjustments still refresh dependent fee definitions.
PUT /listings/{id}/parentcan now group a child with no published statement history when its current in-review statement matches a published parent statement by dates and currency. Published child history and non-zero pre-close activity remain blocked.- Plaid configuration and
POST /accounts/{id}/banking-initcan now create an explicit opening balance before the team selects its statement start date. Regular transaction writes still require the accounting start date. - Bank-record CSV previews now accept null unused mapping columns from completed task output. Signed mappings can leave debit and credit null, debit/credit mappings can leave their signed source null, and clients can submit the reviewed mapping unchanged when confirming the import.
GET /reports/journal-entriesand its CSV export now return an empty result when a non-emptyentityTypesselection maps to no supported journal relation. UI empty-state display values can no longer produce invalid SQL.- Ramp connection now automatically activates the unconfigured
pushRampAccountslistener and starts a full Category synchronization whenautoExtractis enabled or omitted. Reconnect preserves an explicitly inactive listener. Payment preview can reportrampCategoryAccountNotReadyonly while that asynchronous push is pending or after it fails. - Concurrent
POST /statementsrequests for the same ownership period are now serialized before financial detail is calculated. A retry reuses the committed statement and journal attachments instead of applying stale empty financials. UsePUT /statements/{id}when changing status. - Reservation journal refresh now returns a structured
journalEntrieslock when changing only unlocked rows would split a balanced posting group. The refresh writes nothing; genuine journal calculation imbalances remain internal errors. - Scheduled recurring expenses no longer retry owner-side occurrences that fall inside an inactive listing ownership period. No transaction is created for that date; interactive creates and template runs remain rejected.
- Background connection, line-mapping, recurring-fee, recognition, and tax-rate changes no longer schedule journal refreshes for legacy reservations missing their canonical listing link. Explicit reservation refresh still reports the invalid data so it can be repaired rather than posted to an inferred listing.
2026-08-11
-
Added additive dashboard roles backed by versioned
ui:*permission bundles. Team Admin handles access, settings, API keys, integrations, and ACH setup but does not execute ACH; ACH Payer is a separate role. -
GET /team/permission-bundlesandGET /team/permissionsexpose stable string names for role selectors.PUT /team/members/{userId}/permission-bundlesreplaces a member's roles, andGET /mereturns assigned bundles plus effective permissions. -
Added
GETandPUT /team/partner-permission-policy. A selected team can deny primitive permissions to partner-derived dashboard sessions, API keys, and embedded sessions without restricting direct team members. -
Existing admins receive Team Admin; partner-team admins also receive Partner Admin; existing users receive Accountant. Operations covers expense editing and owner-statement publishing without bank management, reconciliation, or general reports. Accountant retains broad day-to-day accounting access with read-only settings. V1 roles and partner policy are team-wide, not bank-account-specific.
-
Recurring-fee adjustment mutations now recalculate chained formula fees in the same targeted journal refresh. For example, changing a cleaning-fee adjustment updates Management Commission when its formula reads the cleaning posting account, while unrelated recurring fees remain unchanged.
-
Recurring-fee listing-period writes now preserve inheritance when their rate equals the definition default. Changing a definition default carries those periods to the new amount and refreshes unlocked reservation journals, while distinct listing-specific overrides remain fixed.
-
DELETE /statements/{id}now rejects statements referenced by payout transaction lines, including requests withonLocked=unlockAndDelete. UsePUT /statements/{id}for lifecycle transitions so the statement ID and payout association remain stable. -
Grouped owner statement list and detail now use only the parent listing's authoritative opening balance. Legacy child balances no longer inflate the first statement after grouping.
-
PUT /listings/{id}/parentnow rejects a child with a non-zero opening balance, including during dry-run. Clear the child balance before grouping, then set the opening balance on the group parent. -
Reservation journal refresh now orders formula-dependent recurring fees only across overlapping listing periods for the same listing. Adjacent historical and future fee definitions no longer create false cycles that can calculate a management commission before its channel-fee deduction. Deployments do not rewrite existing journals; refresh affected, unlocked reservations to apply the corrected calculation.
2026-08-10
PUT /statements/{id}now treats the current status as an idempotent read, and transitions betweeninReviewandpublishedpreserve their existing journal attachments. A current projection avoids accounting writes; a stale projection refreshes without detaching entries. A repeated published request can still request email delivery.- Owner statement payout preview and execution now validate the requested date
against the listing's current statement-period lock. Preview returns
statementPeriodLockedwith structuredopenFrom, and execution creates no payout transaction while locked. SelectopenFromor a later date and preview again. - Reservation detail, list, paid-status filters, and owner-statement rows now
recognize an owner-direct co-host reclass that completes the remaining guest
balance after an earlier deposit.
payment.expectedandpayment.receivedremain the full guest charge when their active A/R total settles it; genuine co-host payouts retain manager-only collectibility. - Reservations spanning the accounting start now apply inactive pre-start owner adjustments to opening A/R and its matching opening-balance assignment. Reversing imported charges before the start date and replacing them after it no longer stacks both amounts into the guest total.
POST /teamsnow allocates generated slugs from the global tenant registry and validates explicit slugs there before regional creation. A name already used in another region receives the next available suffix instead of failing provisioning after email verification.- Plaid Link sessions for Hostaway-region teams now select the
hostawayDashboard customization with its required United States country scope and theHostawayclient name. This applies to create, update, and replace flows; all other regions use theVRPlatformclient name and default United States and Canada customization. POST /connections/{id}/csv-importnow validates importers against canonical integration capabilities. A stale regional app projection no longer rejects a supported Booking.com payout CSV, and invalid importer requests are rejected before import state or transit files are created.- Breaking: payment authorization now separates accounting records from
external money movement.
transactions:payis replaced bytransactions:mark-paid, andstatements:payis replaced bystatements:record-payout. provider: "ramp"onPOST /transactions/{id}/payandPOST /statements/payadditionally requiresach-payments:execute. Unlinking a Ramp provider attempt requires that scope plustransactions:mark-paid.provider: nullnever requires the ACH scope.POST /contacts/{id}/payment-methods/achnow requires the isolatedach-payment-methods:writescope instead ofcontacts:write.- Added
partner:payments:v1for read and record-only payment workflows and additivepartner:ach-payments:v1for ACH setup and execution. Restricted keys must combine both bundles to trigger Ramp payments. GET /apps,GET /apps/{id},GET /connections, andGET /teamnow use canonical integration capability metadata. Stale regional metadata no longer hides supported Hostaway reservation or Stripe payout Fetch actions; storedsync: "none"capabilities remain excluded.- Ramp statement payout preview and execution now require current
chart-of-accounts synchronization evidence for the
payout_distributionCategory. Preview returnsrampCategoryAccountNotReady, and execution creates no payout until a newer full Ramp account push or exact account-event push completes. POST /transactions/{id}/payapplies the same check to every outbound Ramp bill Category and returns422before creating a provider-payment request. Existing Ramp connections without identifiable sync evidence must run the Ramp chart-of-accounts flow once before their next Ramp payment.
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.
