One organisation, as staff see it
const url = 'https://api.sloose.com/staff/orgs/org_9f3c';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url https://api.sloose.com/staff/orgs/org_9f3c \ --header 'Authorization: Bearer <token>'Backoffice route: a staff session, or ADMIN_TOKEN. The organisation, its entitlements resolved fresh, everyone in it, its connectors, its invitations and its newest runs — what a support conversation needs, read-only. Looking is written down, so an organisation can later see who looked.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”The organisation
Example
org_9f3cThe organisation
Responses
Section titled “Responses”The organisation.
object
object
Whether the organisation has had its trial — one per organisation, running or over — read as the trial route’s own refusal (ORG_ALREADY_TRIALED) reads it, so a page that offers the tool and the tool cannot disagree. A reservation whose request died is no trial.
When its trial ends or ended; null when it has not had one, or while one is still being started.
A trial’s reservation is live: a start is in progress (or died less than its lease ago). It blocks a second start but is not yet a trial; it settles, or lapses, within minutes.
Everything the widget needs to know about what this organisation may do.
object
object
object
object
CRM users allowed to use the widget; null = unlimited.
Connections the organisation may hold — a sandbox is a connection like any other; null = unlimited. A file is not one.
Import runs per period, each counted once at the first row it sends to be written, whether or not the CRM takes that row; null = unlimited (fair use). Dry runs never count, and neither does a free retry (Retry failed of a run with failed rows, at most three in a row, each spent at its first admitted row: one that ends having admitted none is given back) while the rows it writes are its chain’s: one that writes a row new to its chain past the rows the chain was counted for is counted at that row. This is judged by key only while the chain’s keys are kept: a day after the chain last ran, or for a chain begun before keys were kept, a link’s rows are judged by the count it declared instead, as they were before, and no run is counted at a later row.
Imports that may be running in the organisation at once, dry runs aside; null or absent = no limit. A run past it is refused at authorise with LIMIT_RUNS_CONCURRENT.
The most rows one import set may declare. Checked before anything is written.
Server-side runs only. Browser runs are never refused on it.
USD per 1,000 rows beyond rows_per_month, server-side runs only; null = not offered.
Bytes of uploaded files the organisation may hold at once; null = no limit, absent = the plan offers no files. Checked when an upload is reserved: past it, only NEW uploads are refused, with LIMIT_FILES_BYTES; nothing stored is deleted early.
Days a stored file is kept after its last use (a run that used it, naming it in a sheet, or its upload); absent = the longest any plan keeps one.
object
object
object
Runs counted this period, through any of the organisation’s connections: each once, at the first row it sent to be written, whether or not the CRM took that row.
AI credits. Included credits reset each period; purchased ones do not.
object
Included + purchased − reserved
Applies right now regardless of the action.
The space the organisation’s files take, against limits.files_bytes.
object
Bytes of uploaded files the organisation holds now: each stored file’s real size and each reserved upload’s declared size (“Files in Sloose”). Counts only: never a file’s name or key.
object
The invitation’s, or what an administrator set here. A sign-in never changes it.
The person is banned — refused in every organisation, not just this one.
The person is a member of Sloose staff.
The person has a second factor enrolled: a verified authenticator app or a passkey.
object
The kind of system it connects: zoho_crm in this build. A row a later build wrote may name a kind this one does not know, and is returned as stored.
Source | destination | both
What people call it — the connected system’s own name for the account until an administrator renames it (for zoho_crm, the CRM’s company name).
Whether a verified user of the CRM may be told this organisation holds it and ask it for access. An administrator turns it off for an organisation that would rather not be listed.
The system’s own id for the account (for zoho_crm, the Zoho organisation id).
The system’s region or data centre, where it has one (for zoho_crm, the Zoho data centre).
A person’s own connection (design §14.6): theirs alone, never an API token’s, managed by nobody else — and never named to the CRM’s users, whatever listed says.
Whether it holds a usable credential, so the server can read the system with nobody present.
Ok | revoked | error, from the credential’s last use.
Whether the grant covers the records themselves, which an import searches and writes. A connection made before connecting asked for them holds sign-in’s scopes alone: it is connected, can be read, and needs reconnecting before an import can run through it.
Whether the system lets the grant ask its query API, by the system’s own answer to a query through it (for zoho_crm, Zoho’s): true once answered, false once refused for want of the permission (the connection then needs reconnecting, since the permission is asked at connect), null until something asked. Discovery asks it once.
Whether the system lets the grant read a module’s layouts, by its own answer: true once answered, false once refused for want of the permission (ZohoCRM.settings.layouts.READ), null until discovery asked, which it does only of a CRM that has a subform. A subform’s row limit and the columns its layout requires are unknown while it is false; reconnecting gives the permission. It never makes a connection needsReconnecting by itself.
Whether the system lets the grant upload a file for a file field, by its own answer: true once answered, false once refused for want of the permission (ZohoCRM.files.CREATE), null until discovery asked, which it does only of a CRM that has a file field. A file field cannot be imported into while it is false; reconnecting gives the permission (an attachment needs only the records permission and is not held by it). It never makes a connection needsReconnecting by itself.
Whether a refusal of this connection’s grant is most likely the system’s own cap on grants (#1852). For zoho_crm: Zoho keeps 20 live grants per person per client and silently ends the oldest when one more is made, and the person who granted this one has made that many since. Reconnecting it ends their oldest other connection in turn. False for a connection whose grant is not refused, or was refused for any other reason as far as Sloose can tell.
The modules whose field annotations a push from a configuration repository (POST /orgs/{org}/config/bundle, what sloose push sends) has written, each with when it last did; empty when none has. A push writes each of those modules’ annotations whole — and only those modules’ — so an alias added in the app on one of them is taken away by the next push that does not carry it, and one on any other module stays (a push still sets every module’s curation and excluded fields from its modules.json). Written with those annotations, never read from the audit.
object
The module’s CRM API name.
When a push last wrote its fields.
Whether the connection’s system has a file field an import can write (discovery found one, and it is not read-only). What decides whether the page offers “reconnect to import files”: a file field an import cannot write yet is nothing to reconnect for.
Whether the caller may change this connection’s field annotations, its aliases among them: true when the caller’s role, as this request settles it, is administrator. An API token acts at the lower of its own role and its creator’s (#239), and a read-only staff view writes nothing. False in the backoffice, which changes none.
object
The newest ten.
One import run. Retired nightly past the plan’s history window.
object
The connection this run wrote to: its import’s, or the one the authorising request named — a run always names one, for a token as much as for a person (design §14.8). Null only on a run recorded before connections were named.
The import this run ran; null for a run recorded before imports were stored.
dry writes nothing and is free. retry is a run charged as a FREE LINK, which counts no second run: a retry of a run’s failed rows, or a resume of a run its page left or a spent day stopped (#1659, #1969). A retry or a resume charged as a new run is real, like any run of its own. A free link is spent at its first ADMITTED row: one that ends with none admitted costs its run nothing and is handed back (the run can be retried free again), and a retry or a resume that names it stands below the run it named. What a run IS, a retry or a resume, is what it stands on and what it carried (GET …/runs/{run}/inherited), never this. A free link is free while the rows it writes are its chain’s, by their rowKey: one that wrote a row new to its chain past the rows its chain was counted for was counted as a run at that row, and still reads retry here. This is judged by key only while the chain’s keys are kept: a day after the chain last ran, or for a chain begun before keys were kept, a link’s rows are judged by the count it declared instead, as they were before, and no run is counted at a later row.
How many free links in a row are left below this run: the chain’s three (a run of its own, which heads a chain once the period counts it, keeps all three) less the free link this run is. A free link is a retry or a resume (#1659, #1969); a resume of a run a spent day stopped takes none of the three. A retry of this run is free only while this is above 0, and only if the run ended as the client said, with failed rows, and has had no free link spent already (one that admitted a row). A free link keeps the meter’s own answer; on any other run it is worked out from the history, and is 0 when the history cannot walk the run’s chain to its top (the purge took a run above it), which the meter reads as not free. The meter keeps every link, and may still charge such a retry as free.
The run this one was charged as a FREE link of (kind retry): the run it retried, or the run it picked up where a resume was free (#1659, #1969). Null for any other run — a retry or a resume charged as a new run included, whose inheritance says what it stands on (GET …/runs/{run}/inherited) — and once the history’s purge has taken the run it named.
The template version the import had copied when this ran.
The import’s version when the run took it: what the run ran is what that version said.
authorised is the server opening the run; running, complete, cancelled and error are the client saying how it went. over_limit is the SERVER stopping one that reported past the rows allowed in a single import — the error field then carries which limit and what it was, because the status on its own tells nobody. refused and abandoned belong to an import’s run: the ledger refusing one whose claim was already taken (the claim is released at once), and the server closing one whose client stopped renewing its lease.
What stopped the run, where the server saw it: allowance when a call of the run was refused because the CRM’s API allowance for the day was spent, and its page then closed it cancelled, or went before it closed and the server ended it abandoned. Its rows were not failed by that: the ones it had begun are kept with the run as left (not_reached in its records) and a resume takes them again, free of a run each time (dayLink on authorise). Null for every other run, and always for one whose status is neither cancelled nor abandoned — over_limit says what ended that run, and a run that finished was not stopped. Written by the server as it relays the refusal, never taken from the page.
Whether the run’s own page said it ended in order: it finished every call of every row it began and stopped at the top of a window (a person’s Stop, or the run’s own stop at the first failure), or reached the end of the file. The engine’s word, carried by the closing report as inOrder and kept only where the ledger ended the run as that close said, or stopped it at its row limit before the close arrived (over_limit: the limit refuses a row before its first write, so the page that ran it still knows whether every row it began was finished), the server saw nothing stop it (stoppedBy is null) and holds no unanswered attempt of it; the page leaves it out when an outcome report of the run was given up on or refused. Cleared by an unanswered attempt stored for the run after its close; never worked out from the status. True too for a complete the server wrote because the engine said it finished (#2237) and its page went before its close. False for a run a spent allowance stopped, one a sign-out, a reset or a replaced session ended mid-window, one the server ended without that word (abandoned, or over_limit whose page went before it closed), and a run recorded before this was kept. A reopened run whose last window may be unfinished is gone over from it, and one that is closedInOrder is not.
Whether a retry may follow this run (retryOf on authorise), by the run’s own record: it has ended, however it ended, it was no dry run, and the history’s purge has not begun to take it (purgeStartedAt) — whatever it wrote. A retry of it inherits what its chain made. It says nothing of what the authorisation asks for itself, which may still refuse a retry of it. Among those refusals, each a 409: RUN_SUPERSEDED (the import has been run past it), RUN_SETTLING (its last writes are not yet written down), RUN_RECORDS_LOST (they could not be) and CONNECTION_MISMATCH (a run of its chain wrote to another connection than the import’s). Whether a retry is FREE — no second run counted — is narrower again, and the ledger’s: only of a run that ended complete, error or cancelled with failed rows and had no free retry spent before (a link that ended with no row admitted is given back, and a retry naming it stands below the run it named), and no more than three free retries in a row below a run the period counted. Any other retry the authorisation allows is charged as a new run: of a run with no failed rows, one whose free retry was spent already, one that is already the third free retry in a row, a run that was never a link and sent no row (it costs nothing and is not counted), or one stopped at its row limit (over_limit) or abandoned.
When the nightly purge began to remove this run, past its plan’s history_days; null until then. Its records go before its row — and its row stays when they would not all delete — so from then on what it made cannot be read in full, and a retry of it is refused (409 RUN_RETIRED).
Who ran it, joined from the user row rather than left as an id — a person who has since left the organisation is in no member list the caller could look them up in. An API token acts as its creator, so this is filled in for a token’s run too: read tokenId/tokenName before attributing a run to a person.
The organisation API token that authorised it, or null for a person. Set from the session, so a run made with a token is distinguishable from one the same person made in the browser.
What that token is called, joined from the token row. Survives revocation, because revoking keeps the row.
What the destination is called here, joined from the connector row. Null exactly when connectorId is — see the three causes there, only two of which are historical.
Where the runs after these ten carry on: the cursor for GET /staff/orgs/{orgId}/runs. Null when these are all of them.
Example
{ "entitlements": { "plan": { "key": "free" }, "status": "free", "warnings": [ "LIMIT_ROWS" ] }, "members": [ { "role": "operator" } ], "connectors": [ { "kind": "zoho_crm", "status": "active" } ], "invitations": [ { "status": "pending" } ], "runs": [ { "kind": "real", "mode": "widget", "status": "authorised", "stoppedBy": "allowance" } ]}A bearer that is neither the token nor a live session (code: AUTH_REQUIRED).
The error envelope every non-2xx answer uses.
object
Human-readable explanation.
Machine-readable reason. Absent on a few legacy 400s.
Examplegenerated
{ "error": "example", "code": "example"}A customer’s session, an API token, or no bearer at all — not staff, and not the ADMIN_TOKEN (code: ADMIN_REQUIRED).
The error envelope every non-2xx answer uses.
object
Human-readable explanation.
Machine-readable reason. Absent on a few legacy 400s.
Examplegenerated
{ "error": "example", "code": "example"}No such organisation, or it is not visible to this session.
The error envelope every non-2xx answer uses.
object
Human-readable explanation.
Machine-readable reason. Absent on a few legacy 400s.
Examplegenerated
{ "error": "example", "code": "example"}The restore switch is on (code: MAINTENANCE): every route but /health and /robots.txt is refused before anything is read, except the operator’s own POST /staff/people/{id}/delete with the ADMIN_TOKEN. Sloose is down for maintenance. Please try again in a few minutes.
object
Example
{ "code": "MAINTENANCE"}Headers
Section titled “Headers”Seconds until asking again is worth it (300 while the switch is on).