/api/v1/accounting/xero/start
auth: jwt (administrator)Begin a Xero OAuth2 authorisation flow for the caller's business. Generates a PKCE verifier + state, persists them in OAuthStates, and returns the Xero authorisation URL the app/browser must redirect to. Rate-limited (10/min open bucket).
handlers: XeroAuthController.start
No parameters.
APIResponseDataObject<XeroStartResponse>APIErrorAPIError/api/v1/accounting/xero/callback
auth: noneOAuth callback target hit by the user's browser after Xero consent. Validates the state (constant-time), exchanges the authorisation code, upserts XeroConnections rows for every tenant returned, and either 302-redirects (desktop) or serves a 200 text/html bridge page (mobile UA) that opens the native `vsms://auth/xero/...` deep link.
handlers: XeroAuthController.callback
| name | required | default | description |
|---|---|---|---|
code querystring | no | — | OAuth authorisation code returned by Xero on success. |
state querystring | no | — | Opaque PKCE state value previously issued by `/start`. Constant-time compared against OAuthStates row. |
error querystring | no | — | Set by Xero when the user denies consent or the flow fails. Triggers the failure bridge / failure deep link. |
error_description querystring | no | — | Human-readable error message from Xero (logged, sanitised before being exposed). |
redirecttext/html/api/v1/accounting/xero/status
auth: jwtConnection summary for the caller's business — whether a Xero connection exists, the active tenant, the list of authorised tenants (no tokens), and the current `autoFiscaliseInvoices` flag.
handlers: XeroAuthController.status
No parameters.
APIResponseDataObject<XeroStatusResponse>APIError/api/v1/accounting/xero/tenants
auth: jwtList every Xero tenant authorised for the caller's business. Each entry carries `isActive` to indicate which tenant is the current target of sync / webhooks.
handlers: XeroAuthController.tenants
No parameters.
APIResponseDataList<XeroTenantSummary>/api/v1/accounting/xero/tenants/:xeroTenantId/activate
auth: jwt (administrator)Switch the active Xero tenant for the caller's business. Flips `IsActive` on XeroConnections rows so subsequent sync / webhook traffic uses the chosen tenant.
handlers: XeroAuthController.activateTenant
| name | required | default | description |
|---|---|---|---|
xeroTenantId pathuuid | yes | — | Xero tenant GUID to mark active. |
APIResponseDataObject<XeroTenantSummary>APIError/api/v1/accounting/xero/connection
auth: jwt (administrator)Hard-disconnect Xero for the caller's business — deletes every XeroConnections row, drops encrypted tokens, fires `XERO_DISCONNECTED` audit.
handlers: XeroAuthController.disconnect
No parameters.
APIResponseDataObject<{ deletedCount: number }>