Batch Imports
Submit source data through the product API batch endpoints
Submit source data through the normal product API batch endpoints. There is no separate ingest surface: batches use the same host, credentials, validation, locks, and dry-run behavior as every other operation.
POST https://api.vrplatform.app/reservations/batch
x-api-key: <team-api-key>
x-team-id: <team-uuid>Available Batch Operations
The exact request schema and per-entity fields live on each generated page.
Identity and Idempotency
Send a stable uniqueRef per item. Resubmitting the same uniqueRef updates
the existing record instead of creating a duplicate, so to retry safely,
resend the batch. The rules for stable identity, conflict handling, and
irreversible side effects live in
Integration-sourced data.
Outcomes
A batch responds with per-item results and structured issues:
{
"data": [
{
"id": "11111111-1111-4111-8111-111111111111",
"uniqueRef": "pms-res-1042",
"sourceId": null
}
],
"issues": []
}Process data and issues item by item; a batch is not all-or-nothing.
Validate risky batches first with dry run where the
operation declares the dryRun parameter.
Asynchronous Operations
Long-running endpoints return after VRPlatform durably records the work. Each endpoint documents its request and returns the same operation envelope:
{
"operationId": "op_dQyc6IHtQbmwTn-TMMWD7Q",
"type": "csv-import",
"status": "queued",
"resource": {
"type": "connection",
"id": "11111111-1111-4111-8111-111111111111",
"role": "target"
}
}operationId is the stable, opaque status identifier. New identifiers use an
op_ or act_ prefix. Existing UUID identifiers remain valid during the
compatibility period. Store and return the complete value without parsing its
prefix. type identifies the public operation category. resource identifies
its primary source, target, or result when one exists; it can be null for
multi-resource work.
Read one operation
GET /operations/{id}Replace {id} with the operationId returned by the initiating endpoint.
curl \
-H "x-api-key: $VRPLATFORM_API_KEY" \
"https://api.vrplatform.app/operations/op_dQyc6IHtQbmwTn-TMMWD7Q"{
"id": "op_dQyc6IHtQbmwTn-TMMWD7Q",
"type": "csv-import",
"status": "running",
"resource": {
"type": "connection",
"id": "11111111-1111-4111-8111-111111111111",
"role": "target"
},
"resources": [
{
"type": "connection",
"id": "11111111-1111-4111-8111-111111111111",
"role": "target"
}
],
"failure": null,
"createdAt": "2026-08-15T13:45:10.123Z",
"startedAt": "2026-08-15T13:45:12.456Z",
"finishedAt": null
}| Status | Meaning |
|---|---|
queued | The operation is durably recorded and waiting for execution. |
running | A worker is executing the operation. |
completed | All work owned by the operation completed. |
failed | The operation reached an unsuccessful terminal state. |
createdAt is always present. startedAt records the first start and can stay
set during recovery. finishedAt is set only for completed or failed.
Operations with several required sources remain non-terminal until every
source settles. The API does not expose child progress.
Poll until the operation reaches completed or failed. Start with a short
interval and back off while the status remains non-terminal. This API exposes
observation only; it does not provide public retry or cancellation controls.
Track reservation journal recalculation
A journal-relevant PUT /recurring-fees/{id} returns the accepted operation
inside the recurring fee response:
{
"id": "3cb5eb9e-c5d7-4268-8f40-2d4df2819702",
"name": "Management fee",
"operation": {
"operationId": "act_VQ6EAOKbQdSnFkRmVUQAAA",
"type": "reservation-journal-refresh",
"status": "queued",
"resource": {
"type": "recurring-fee",
"id": "3cb5eb9e-c5d7-4268-8f40-2d4df2819702",
"role": "source"
}
}
}operation is null when the update queues no reservation journal work. Dry
runs also return operation: null.
Reservation, recurring fee, and owner statement reads include the same
operation in their operations summary while the recalculation is queued or
running. They also include journalStatus:
| State | Meaning |
|---|---|
current | Every known journal change in the resource scope is applied. |
recalculating | At least one outstanding change has queued or running work. |
failed | Outstanding work reached a terminal failure. |
stale | The journal has outstanding change without active recovery work. |
Poll GET /operations/{id} instead of repeatedly refetching the heavier
domain resource. Refetch the visible resource once the operation becomes
completed or failed, then trust the returned journalStatus; operation
completion alone does not prove that every scoped journal change is applied.
Share one poll when several visible resources contain the same operation ID.
Authenticated owners can poll a reservation-journal-refresh operation only
when an affected reservation is within their owner access. Operations outside
that access return the standard not-found response.
Find operations after refresh
Use GET /operations to filter retained history by resource, type, status, or
creation time. The response includes cursor-paged items, the retained match
total, and queued, running, completed, and failed counts.
Completed operation history is retained for 90 days. An unresolved failed journal refresh remains available until later work applies its outstanding journal change; the normal 90-day window starts after that recovery completes.
Pass type=reservation-journal-refresh&initiatedBy=me to show refresh work
attributed to the authenticated user. Omit initiatedBy for the team-wide
support view. Each operation returns either a user initiator with userId or a
system initiator.
Supported team, connection, contact, listing, reservation, recurring fee,
statement, transaction, flow, bank-rule, recurring-template, and webhook reads
also include an operations summary. Its counts cover retained history. Its
items contain queued, running, and latest unresolved failed work, so a
refreshed UI does not need a saved operation ID or one request per resource.
Read import and export results
CSV preview and import result endpoints use the operationId in their normal
typed result path after completion. They do not read execution-provider state.
Use a documented generating GET route when the selected export is bounded to
finish within one minute. It returns a signed download URL when generation
finishes and does not create an operation.
Use the matching POST route for durable background work, larger supported
selections, or whenever the caller needs status that survives the initiating
request. The queued operation uses a file result resource. After it completes,
read its resources and download the file through:
GET /files/{fileId}/downloadIf a GET selection exceeds its awaited budget, the API returns
EXPORT_REQUIRES_POST. Send the same selector to POST and follow the returned
operation instead.
Authorization and privacy
Operation detail and history require operations:read. Every Partner or
embedded bundle that can start queued work and every UI permission bundle
grants that scope; no separate polling credential is required.
An operation belongs to the requesting tenant resolved when it was created,
not to a target entity named in its request. For example, a VRI import created
with a Partner credential belongs to that Partner tenant; a token belonging to
the target team receives 404 for its id. Unknown identifiers, unsupported
internal action types, and identifiers owned by another requesting tenant all
return 404.
The response never exposes request payloads, raw errors, effects, attempts, provider steps, or runtime identifiers. Failed operations can expose only a stable code and static safe message. Internal, non-allowlisted work is not readable through these endpoints.
Poll through MCP
Use vrt_api_read; Partner paths do not require teamId:
{
"path": "/operations/op_dQyc6IHtQbmwTn-TMMWD7Q"
}For API-key authentication, MCP preserves the credential tenant and does not
send x-team-id for this read. OAuth users supply the team that initiated the
operation through teamId or the MCP connection's team_id.
Related
- All asynchronous operation endpoints
- Connections for continuously synced sources
- Historical statements and historical journal entries for pre-go-live history
