Connections¶
A connection is one (org, app) consent grant. A user can hold several — one per organisation they've connected your app to. Nothing in the token tells you which org a request is scoped to at any given moment except the URL you call.
Connecting more organisations¶
Send the user through the same authorize URL again. There is no multi-select — consent is one organisation per pass, the same Xero-style flow used to connect the first one.
If the user is already logged in to LuciBook (the normal case: they just finished connecting their first org, or they still have a session), they are not prompted to log in again — they land directly on the consent screen and pick another organisation from the picker. If they pick an organisation they've already connected your app to, re-consenting there just updates that connection's granted scopes; it does not create a duplicate or disturb any other organisation's connection.
A new connection is created alongside their existing ones each time they
pick a fresh organisation — this is how a user accumulates connections to
several organisations with the same app registration, without you
registering a second client, and without you ever needing a second token.
The access token you already hold identifies (your application, this
user) only, not any one organisation — so every token you've been issued
for this user already reaches every organisation they've connected, past
and future, the moment each connection exists. You don't need to re-issue
a token after the user connects another org; you only need to learn the
new org_id (see List your connections below)
and start calling it.
A token reaches every org it's connected to, but what it can actually do
there is limited per request to the intersection of the token's own scopes
and that org's connection granted_scopes (the granted_scopes array
shown per item in List your connections) — see
Effective scope, in plain words below for
the full four-way check. Re-consenting to an org updates that connection's
granted_scopes for every token, but a token's own scope is fixed at
issuance — so an older token, issued before a re-consent that widened the
requested scopes, still can't exceed the narrower scope set it was minted
with. If a later consent to the same org requested extra scopes, use the
token issued at that consent to exercise them there.
Per-org access is still enforced on every request, independent of which token you use — see Effective scope, in plain words below for the role/policy/revocation checks that run per call.
List your connections¶
GET /api/v1/connections
Authorization: Bearer <access token>
Returns every active connection the token's own user holds for your application, across every organisation they belong to:
{
"items": [
{
"id": "…",
"org_id": "…",
"application_id": 4821,
"granted_scopes": ["bills:read", "invoices:read"],
"granted_at": "2026-09-01T10:00:00Z",
"revoked_at": null,
"revoked_reason": null,
"last_used_at": "2026-09-20T08:12:00Z"
}
],
"count": 1
}
There is no separate "list my orgs" call — this response is where you learn
which org_ids you can address in other endpoints' URLs.
application_id is your application's internal LuciBook id (a sequential
numeric id, not a UUID) — it identifies which of your registered apps the
connection belongs to. It is not a secret and carries no authority by
itself; every request is still authenticated by the bearer token.
Revoke a connection¶
DELETE /api/v1/connections/{connection_id}
Authorization: Bearer <access token>
Only revokes a connection belonging to the same token's own user and your
own application — a connection id alone is never enough authority.
204 on success, 404 if it doesn't match. The organisation's OWNER/ADMIN
can also revoke from My Apps → Connected Apps, independent of your app.
Who may grant or revoke what¶
- Granting a scope at consent requires the granting OrgMember to hold at least the scope's minimum role tier — see Scopes and role tiers.
- Revoking is available to the app itself (the connection's own user, via the API above), or to any OWNER/ADMIN of the connected organisation from the org's Connected Apps page — independent of the app.
- Revoking also happens automatically if the member who granted the
connection is removed from the organisation, demoted below a scope they
granted, or deletes their LuciBook account.
revoked_atis stamped andconnection.revokedfires exactly as it would for a manual revoke — you don't need to poll for this, only subscribe to the event.
Effective scope, in plain words¶
What a request can actually do is the intersection of four things, recomputed on every request (never cached from token issuance):
- the scopes the token was issued with,
- that organisation's connection
granted_scopes— a different org the same token reaches can have a different (narrower or wider) set, - the scopes the app is still allowed to request today (an app can lose a restricted capability after a token was issued), and
- the granting member's current role tier — checked against the whole
effective scope set from steps 1–3, not per-endpoint, using the same
per-scope role table consent uses (see
Scopes and role tiers). If the grantor is no
longer an active member, or any scope in the effective set now exceeds
what their current role may hold — including
payroll:*andmigration:*, which needOWNERorADMINlive, not only at consent — the whole request fails withinsufficient_role, including a plain read. See Errors —insufficient_rolefor the full rule and how to recover.