Close an authorised run, and record how it went
const url = 'https://api.sloose.com/entitlements/runs/run_7c2e/progress';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"rowsWritten":1,"rowsCreated":1,"rowsUpdated":1,"rowsFailed":1,"done":true,"outcome":"complete","modules":["example"],"inOrder":true,"finished":true,"totals":{"created":"example","updated":"example","failed":"example"},"error":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.sloose.com/entitlements/runs/run_7c2e/progress \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "rowsWritten": 1, "rowsCreated": 1, "rowsUpdated": 1, "rowsFailed": 1, "done": true, "outcome": "complete", "modules": [ "example" ], "inOrder": true, "finished": true, "totals": { "created": "example", "updated": "example", "failed": "example" }, "error": "example" }'Call this once with done: true when the import finishes (or in batches before that, for the history’s created/updated/failed counts). Rows are metered on the write path, not here: every record goes through /orgs/{org}/connectors/{id}/records, which admits the row with the ledger before writing, so this report’s rowsWritten is accepted for older clients and ignored by the meter. The D1 run row is the history; the answer carries the meter’s own total and, when the run has been stopped for reaching the rows one import may write, stopped saying so.
The threshold is the LOWER of the run’s own declaredRows and the plan’s current rows_per_run, and a write that would cross it is refused before it reaches the CRM.
A run ends once, and how it ends is the meter’s (runStatus in the answer): a close that arrives after something else ended the run — the server’s abandoned, when nobody renewed its lease; a stop’s over_limit — is recorded as that ended it, whatever the close says, and a close whose history write was lost is put right by any later report. The history’s rows, and its created, updated and failed counts over every report the meter took, are set from the meter’s snapshot (totals), not added up — and so are they when the server ends the run, which records every row the meter admitted, not only those a report carried. A run of an import reports only while it holds its import: after its lease has run out, anything but a close is refused 409 LEASE_LOST.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”The run id from POST /entitlements/runs/authorise.
Example
run_7c2eThe run id from POST /entitlements/runs/authorise.
Request Body
Section titled “Request Body”object
Rows written since the last report. Non-negative.
Records created since the last report — signed: a negative number takes back one counted before, as a record first counted as created and then found to be an update.
Records updated since the last report — signed, as rowsCreated is.
Rows that failed since the last report — signed: a negative number takes back a failure counted before, as a failed row that succeeds on a later attempt.
True on the final report. Closes the run and settles the meter.
How the run ended. Only meaningful with done: true.
Modules the run touched. At most 50 are kept.
The engine says the run ended in order (it finished every call of every row it began and stopped at the top of a window, or reached the end of the file). Only on the close (done: true), and kept only where the ledger ended the run as that close said, or had stopped it at its row limit before the close arrived, and where the server saw nothing stop it (a spent allowance) and holds no unanswered attempt of it; a late close after the server abandoned the run keeps nothing, and the page leaves the word out when an outcome report of the run was given up on or refused. Never worked out from outcome.
The engine says it FINISHED (#2237): its last window completed — every row walked, none left part-written, no spent allowance — sent before any close, so that a page that goes before its close leaves a run the server can end complete rather than abandoned. Not a close (done absent): it is a report of the run, answered only to the credential that holds its lease, kept only while the run is open, and taken back by an unanswered record stored for the run.
object
With finished: the run’s created, updated and failed rows over the whole run, as its page counted them (#2278). Absolute, never added to anything, so the word can be sent until it is heard. Kept with the run while it is open, and what the server ends the run complete with when its page goes before its close and the run’s records are no longer all held to be counted (past ten thousand). Ignored without finished, on a close, and for a run of no import. A page that sends none leaves such a run to end abandoned, as before.
Failure message, truncated to 2,000 characters.
Responses
Section titled “Responses”The period usage after this report — and, when the run has been stopped for going past the rows one run may write, stopped saying so.
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.
With a run that has ended: the server itself ended it complete on the engine’s finishing word, before this report (#2279). What the run’s history records as who ended it.
With a run that has ended: its close was in order, as the meter remembers it (#2279, #2281). The history keeps it only where it holds no unanswered record of the run.
How many of this report’s rows were counted. Zero for a report against a run that has already finished or been stopped.
Present when the server has STOPPED this run, and on every report after it, so a caller that missed the first answer is told the same thing. Whether THIS batch was counted is credited: the batch that crossed the ceiling was counted in full, and every one after it counts nothing. Stop the import and tell the person why.
With stopped: the number of rows this run was held to.
Was this report taken — which is not the same as how many rows it metered. A batch of only failed rows meters nothing and is still a report about a running import. False for a report against a run that has finished, been cancelled, or been stopped.
Every row this run has been metered for, not just this report’s. The run history is set from it rather than accumulated, so a write that was lost is put right by the next report.
How the run stands after this report, as the meter holds it: authorised while it runs, otherwise how it ended — whatever this report says about itself. A close that arrives after the server ended the run (abandoned: nobody renewed its lease, or nothing was written under a run with no import for a day; over_limit: stopped at its ceiling) is recorded as the server ended it. Absent for a dry run, which the meter never holds.
With an ended runStatus: when it ended, in ISO — the same on every later report. Null for a run that ended before the meter kept the moment.
The run as the meter holds it, in one snapshot: the rows it is held to (written, which is rowsWrittenTotal), the created, updated and failed rows over every report it took, not just this one’s, and their revision. Any of them can fall: a report’s counts are signed, so a correction takes one back, and a write the CRM refused is released from the rows. So the revision moves with every report taken and every row admitted or released, and the run history is set from the newest snapshot. A report whose write was lost is put right by the next, and a slow older one cannot undo it. Absent for a dry run.
object
How many rows this run may write in total. While the run is authorised: the lower of what it declared and what the plan allows in one import, as the plan is now — so it FALLS if the plan is downgraded while the run is going, and a caller that honours it stops on the limit instead of being stopped past it. Once the run has been stopped it is the ceiling it was stopped for and does not move again, whatever the plan does next.
With stopped: which ceiling bound. plan is the plan’s rows per run, which a higher plan raises; declaration is the number this run itself declared, which upgrading cannot change.
With stopped: whether THIS report is the one that ended the run. False on every report after it.
With stopped: when the run was stopped, in ISO. The same value on every later report, so a caller recording it can retry.
Example
{ "stopped": "LIMIT_ROWS_PER_RUN", "runStatus": "authorised", "stoppedBy": "plan"}rowsWritten is negative or not a number.
object
Examplegenerated
{ "error": "example"}No bearer, or one that no longer resolves: a session that is unknown or expired (code: AUTH_REQUIRED), or an API token that was revoked or expired (TOKEN_REVOKED, TOKEN_EXPIRED), whose organisation is gone (ORG_NOT_FOUND) or whose member or user row is (MEMBERSHIP_GONE).
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 run is an import’s and this is not the session or token that authorised it (code: NOT_YOUR_RUN) — a run is closed by the credential that started it; the bearer’s role is too low; or its organisation has been closed (code: ORG_CLOSED). Like every route behind a session: a session signed in but in no organisation is refused code: NO_ORG, a banned person code: BANNED, and a closed organisation code: ORG_CLOSED.
object
Examplegenerated
{ "error": "example", "code": "example"}No such run, or it has already been settled.
object
Examplegenerated
{ "error": "example"}The run is an import’s, this report is not a close, and the run no longer holds its import (code: LEASE_LOST): only a close may come after the lease.
object
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).