Connections
Discover apps, create source identity, complete OAuth, and monitor sync
A connection relates one team to a PMS, booking channel, bank provider, or other external system. It scopes source identity and synchronization; it does not replace VRPlatform resource IDs.
Discover The App
Call GET /apps, choose the exact returned id, and inspect its category,
flows, extractors, importers, and connection requirements. Do not use the
display name as identity.
Create With Credentials
Call POST /connections with partner or team API-key authentication and the
selected x-team-id. Provide appId, optional name, and the credential shape
declared by that app's generated contract.
Creation can queue PMS initialization or provider work. Read the returned connection and sync state instead of assuming all external setup completed in the request.
Browser Extension Credentials
Apps whose authentication.extension is true or an extension settings
object use the browser-extension credential flow. A connect request without
credentials returns ISSUE_EXTENSION so the client can collect them.
Submit extension credentials through params.credentials together with stable
account identity from params.uniqueRef, credential email, or credential
username. The API completes these credentials directly; do not forward them
through any intermediary OAuth flow or treat the issue response as an OAuth
prompt.
OAuth Flow
Use POST /connections/connect as the normal OAuth entry point.
When redirectTo is omitted, the API uses the registered production callback
https://portal.vrplatform.app/callback/. The legacy production value without
the final slash is canonicalized to that registered callback. Other explicit
callback targets are preserved exactly because OAuth providers require an
exact redirect URI match.
- Send
appId, setupparams, and your real callbackredirectTo. - If the API returns
ISSUE_REQUEST_OAUTH, redirect toaction.value, the provider authorization URL. - The provider redirects back to
redirectTowithstateand other params. - Send those callback params unchanged to
POST /connections/connect. - Read the success response and resulting connection.
An ISSUE_REQUEST_OAUTH response looks like this:
{
"type": "issue",
"code": "ISSUE_REQUEST_OAUTH",
"message": "Please provide the missing details to connect this app.",
"state": { "expiresIn": 180000 },
"action": {
"type": "oauth",
"value": "https://provider.example.com/oauth/authorize?client_id=...&state=..."
}
}Callback params go into the request body under params — copy everything the
provider appended to your callback URL, including state, as-is. The state
value resolves the app, so appId may be omitted on the callback request. To
reconnect an existing connection, send the same body to
POST /connections/{id}/connect; a first-time connect uses
POST /connections/connect:
POST /connections/11111111-2222-3333-4444-555555555555/connect{
"params": {
"state": "<state param exactly as received on the callback>",
"code": "<provider authorization code>"
}
}A completed connect returns type: "success" with the connection id and
the connection resource.
Provider account identity is case-insensitive during connection completion. Create and reconnect normalize the returned identity to lowercase, so a casing-only provider change does not make the same login look like a different account. A genuinely different provider identity still blocks reconnecting the selected connection.
redirectTo is your callback; action.value is the provider page. Do not
redirect to the callback before the provider authorizes.
state is a signed token that binds the app, team, setup params, callback,
and optional connection; during the flow it can come back wrapped in an outer
envelope that embeds the signed token. The API verifies the signature and the
team binding, so pass the callback state back exactly as received — a
rebuilt or edited value is rejected. If state is missing, malformed, expired,
or completed under another team, restart the flow.
Synchronization
Use GET /connections, GET /connections/{id}, and
Sync connection to render status, enabled
flows, last fetch, and current failure. Provider sync is an external side
effect and has no generic dry-run guarantee.
For production monitoring and team issues, continue to Operate.
Webhook Reconciliation
Subscribe to connection.changed for committed public connection changes and
sync.status.changed for actual sync status transitions. Credential-only
updates and sync subtask-only changes do not emit. Compare resourceVersion
per resource and fetch the event's href; webhook bodies never contain
credentials or provider response data.
