Take the record a create nobody answered made
const url = 'https://api.sloose.com/orgs/org_9f3c/connectors/cnn_9f2a/records/Accounts/40000000000000101/made';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"runId":"example","rowKey":"example","keys":"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/orgs/org_9f3c/connectors/cnn_9f2a/records/Accounts/40000000000000101/made \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "runId": "example", "rowKey": "example", "keys": "example" }'A create the CRM never answered may have made its record, and the same create sent again is then refused as a duplicate (DUPLICATE_DATA), naming the record that holds the value. The engine asks this route whether that record is the row’s to take, only after such a refusal that follows an unanswered send of the same row and module, and only where one record holds the value and no row of the run or its chain holds it already.
The server reads the record itself and takes it only when the connection’s own CRM user created it, at or after the moment the first run of this import’s chain was authorised — or up to 2 seconds before it, since a record’s creation time is to the whole second and by Zoho’s clock, not this server’s. It cannot tell the lost create’s record from another the same CRM user made in that time with the same unique value — by hand, or through another import — and takes either: it is the record that holds the row’s unique value, which no create of the row can now make. A record somebody else made, or one made before the chain began, is not taken (taken: false, with why), and the refusal stands.
What is proved is who made the record and when, and nothing of what it holds beyond the unique value Zoho refused the create over. So the engine reads the record first, by its id, asks only for one that is there, and from then on treats it as what it read: the keys it sends are the record’s, the row’s later modules read the record’s fields, and a link from another file finds it by the values it holds. held knows the records written under this run and the ones a row of it has taken: a take is reserved for its row as it is admitted, so two rows asking at once, or one after another, cannot both be given one record. A row holds one record to take in a module: asking for another lets the first go, whether or not the other is then its to take, so a row the CRM later names the first for may take it. A record a row only matched and left as it is was never written here, and the engine is what keeps a row from taking one.
Taken, the record is written down as the row’s (created, with the code MADE_EARLIER) under the next attempt number, and an admission kept from the unanswered send is confirmed with it, so later writes to the record under the row cost nothing more. It counts no row and writes nothing to the CRM; it reads twice (the record, and the grant’s own user).
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”The organisation id the session was issued for. A token for one organisation can never read another.
Example
org_9f3cThe organisation id the session was issued for. A token for one organisation can never read another.
The connector id, from GET /orgs/{org}/connectors.
Example
cnn_9f2aThe connector id, from GET /orgs/{org}/connectors.
The module’s API name in the destination.
Example
AccountsThe module’s API name in the destination.
The record’s id in the destination.
Example
40000000000000101The record’s id in the destination.
Request Bodyrequired
Section titled “Request Bodyrequired”object
The run from POST /entitlements/runs/authorise. Required.
The row whose create was refused (rowKey(flowId, row)). Required.
The (field, value) pairs the record is indexed under, kept with it so a later retry resolves a link to it. The record’s own, as the engine read it back before asking, never the refused create’s: only the unique value is known to match what the row sent, and a link by a value the record does not hold must not find it.
Examplegenerated
{ "runId": "example", "rowKey": "example", "keys": "example"}Responses
Section titled “Responses”Whether the record is now the row’s.
object
Why not, when taken is false: another — somebody other than the connection’s CRM user created the record; earlier — it was created before this import’s runs began; gone — no such record now; unread — the record does not say who created it or when, or when this import’s runs began cannot be said: none of them is held, or its chain of runs is longer than is walked (a thousand, and the run itself); held — another row of this run holds it, or this row has been sent again since this take was asked, which makes the later send the row’s word and lets this one go; reused — this row’s module already holds a different record; ended — the run is no longer writing: it has ended, or it is an import’s and no longer holds its import (its close gave the import back, or its lease ran out). That last is answered before anything is asked of the CRM, and as ended, never as the 409 LEASE_LOST a write under such a run is refused with.
Example
{ "why": "another"}No run or row key. Or the module is a subform (SUBFORM_NOT_WRITABLE, written: false): a subform row is never a record a row could take, since its rows are written inside their parent’s record.
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 has been stopped and nothing was written (code: RUN_STOPPED, with stop); the run is an import’s and this is not the session or token that authorised it (code: NOT_YOUR_RUN); or the bearer’s role is too low, or it was issued for a different organisation. 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
object
The error envelope every non-2xx answer uses.
object
Human-readable explanation.
Machine-readable reason. Absent on a few legacy 400s.
Example
{ "code": "RUN_STOPPED", "stop": { "stopped": "LIMIT_ROWS_PER_RUN", "stoppedBy": "plan" }}No such connector, or it is not visible to this session (NOT_FOUND); no such run (RUN_NOT_FOUND); or the connection has no module of that name — only its modules, as its discovery read them, are asked of the CRM (MODULE_NOT_FOUND).
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 was authorised for a different connector (RUN_CONNECTOR_MISMATCH). A run that is no longer writing is not a conflict here: it is answered taken: false, why: "ended".
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"}Zoho refused a read.
object
object
True when Zoho gave no answer that says what was done — the connection dropped or timed out, Zoho failed on its side (a 5xx, or the same for the one record inside a 2xx), the answer was lost after its status or was not JSON, or Zoho said it made the record without saying which — so what was asked may have been done all the same: a create sent again after one may make a second record. A write that went unanswered stays counted, and its row may be written again for nothing. False when Zoho answered by declining (a 4xx, or a per-record refusal inside a 2xx), which made nothing.
True when Zoho asked for fewer calls and declined this one (TOO_MANY_REQUESTS): nothing was done, and the same call a little later may land — a write included, since a declined one made nothing. Absent from an older API.
How long Zoho asked to be left alone before the next call, in milliseconds, from its Retry-After; also sent as this response’s own Retry-After, in seconds. Null when it said nothing.
True when the rate limit is the CRM’s daily allowance of API calls used up — a 429 whose X-API-CREDITS-REMAINING says none are left — which waiting seconds does not bring back. Without that header the two limits cannot be told apart, and this is false.
Examplegenerated
{ "error": "example", "zoho": { "code": "example", "status": 1, "details": "example", "retryable": true, "response": "example", "unanswered": true, "rateLimited": true, "retryAfterMs": 1, "quotaSpent": true }}Zoho is throttling how often this connection’s access is renewed — ten tokens from one grant in ten minutes — so nothing was sent (code: CONNECTION_THROTTLED; written: false on a write). Retry-After says when to ask again. The connection is kept: only a grant Zoho refuses ends it. A renewal throttled after the call reached Zoho is Zoho’s rate limit, relayed as a 502 with zoho.rateLimited.
Or the CRM’s API allowance for the last 24 hours is spent (zoho.quotaSpent: true, zoho.rateLimited: true, zoho.retryable: false), said one of two ways. Zoho itself refused the call (zoho.code: TOO_MANY_REQUESTS, credits left 0): relayed as this 429, never a 502, since asking again soon is refused again. Or the tenant’s gate refused it before it was sent, because Zoho had already said so: this API’s own refusal, with no zoho (code: DAILY_ALLOWANCE_SPENT; written: false on a write). Neither carries Retry-After: Zoho’s day is a rolling 24 hours and it names no time at which credits return, so Sloose lets one call a minute through to ask, and the first one answered is the allowance’s return. GET …/credits says whether the day is held spent (spent, spentAt). A system that does name its renewal is answered with Retry-After until then.
object
Why: CONNECTION_UNAVAILABLE (502) when a Zoho token for the connection will not refresh, CONNECTION_THROTTLED (429) when Zoho is throttling its renewal — ten tokens from one grant in ten minutes — and the connection is kept, and DAILY_ALLOWANCE_SPENT (429) when the connected system said a daily allowance the call draws on is spent, which waiting seconds does not bring back.
On a write: refused before the record was sent to the CRM, so nothing was written and a retry makes no second record. Absent from a read.
Example
{ "written": false}Zoho is rate-limiting (zoho.unanswered false: nothing was done), or did not answer — it could not be reached, failed on its side, or answered without saying what it did (zoho.unanswered true: what was asked may have been done). Or this API could not use the connection before anything was sent — a Zoho token that will not refresh (code: CONNECTION_UNAVAILABLE) — and says so on a write with written: false: nothing was written.
object
object
True when Zoho gave no answer that says what was done — the connection dropped or timed out, Zoho failed on its side (a 5xx, or the same for the one record inside a 2xx), the answer was lost after its status or was not JSON, or Zoho said it made the record without saying which — so what was asked may have been done all the same: a create sent again after one may make a second record. A write that went unanswered stays counted, and its row may be written again for nothing. False when Zoho answered by declining (a 4xx, or a per-record refusal inside a 2xx), which made nothing.
True when Zoho asked for fewer calls and declined this one (TOO_MANY_REQUESTS): nothing was done, and the same call a little later may land — a write included, since a declined one made nothing. Absent from an older API.
How long Zoho asked to be left alone before the next call, in milliseconds, from its Retry-After; also sent as this response’s own Retry-After, in seconds. Null when it said nothing.
True when the rate limit is the CRM’s daily allowance of API calls used up — a 429 whose X-API-CREDITS-REMAINING says none are left — which waiting seconds does not bring back. Without that header the two limits cannot be told apart, and this is false.
object
Why: CONNECTION_UNAVAILABLE (502) when a Zoho token for the connection will not refresh, CONNECTION_THROTTLED (429) when Zoho is throttling its renewal — ten tokens from one grant in ten minutes — and the connection is kept, and DAILY_ALLOWANCE_SPENT (429) when the connected system said a daily allowance the call draws on is spent, which waiting seconds does not bring back.
On a write: refused before the record was sent to the CRM, so nothing was written and a retry makes no second record. Absent from a read.
Example
{ "written": false}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).