Apply a configuration bundle
const url = 'https://api.sloose.com/orgs/org_9f3c/config/bundle?connector=con_8f2a';const options = { method: 'POST', headers: { 'If-Match': '"7"', Authorization: 'Bearer <token>', 'Content-Type': 'application/json' }, body: '{"bundleVersion":1,"org":{"dateFormat":"DMY","expressionContext":"example","aiSamples":"allow"},"registry":{"version":1,"modules":[{"seedMappings":"example","key":"example","apiName":"example","label":"example","singular":"example","singularLabel":"example","color":"example","defaultEnabled":true,"uniqueFields":["example"],"defaultDuplicateCheck":{"searchField":"example","searchMethod":"example","expression":"example"},"excludedFields":["example"],"child":{"of":"example","via":"example","parentNeedsRows":true,"pointer":"example","maxRows":"off","layouts":{"additionalProperty":{"name":"example","maxRows":"off","required":["example"]}},"defaultLayout":"example"},"stockEffect":{"field":"example","label":"example","direction":"up"}}],"expressionContext":"example","apiDelayMs":1,"systemExcludedFields":["example"],"dateFormat":"DMY","timezone":"example"},"fields":{"additionalProperty":[{"apiName":"example","description":"example","format":"example","examples":["example"],"aliases":["example"],"excludeFromAi":true,"derived":true,"defaultMapping":{"mode":"column","source":"example","staticValue":"example","staticPickedIn":{"connection":"example","module":"example","id":"example","name":"example"},"transform":"example","skip":true,"searchField":"example","searchMethod":"example","searchExpression":"example","patch":{"when":["pending"],"overwrite":"always"},"files":{"sheet":"example","holds":"name","separator":"example"},"key":true,"keyMethod":"example","keyExpression":"example","onNone":"empty","onSeveral":"ask"},"excluded":true,"requiredForImports":"waivable","writtenAs":"upper","mustBe":{"rule":"example","says":"example"}}]},"libraries":[{"manifest":{"namespace":"example","version":"example","scope":"global","description":"example","functions":[{"name":"example","description":"example","params":[{"name":"example","type":"example","optional":true,"description":"example"}],"returns":"example","examples":[{"call":"example","result":"example"}],"tags":["example"]}]},"source":"example"}],"templates":[{"name":"example","description":"example","config":{"additionalProperty":"example"}}],"projects":[{"name":"example","description":"example","config":{"additionalProperty":"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/config/bundle?connector=con_8f2a' \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --header 'If-Match: "7"' \ --data '{ "bundleVersion": 1, "org": { "dateFormat": "DMY", "expressionContext": "example", "aiSamples": "allow" }, "registry": { "version": 1, "modules": [ { "seedMappings": "example", "key": "example", "apiName": "example", "label": "example", "singular": "example", "singularLabel": "example", "color": "example", "defaultEnabled": true, "uniqueFields": [ "example" ], "defaultDuplicateCheck": { "searchField": "example", "searchMethod": "example", "expression": "example" }, "excludedFields": [ "example" ], "child": { "of": "example", "via": "example", "parentNeedsRows": true, "pointer": "example", "maxRows": "off", "layouts": { "additionalProperty": { "name": "example", "maxRows": "off", "required": [ "example" ] } }, "defaultLayout": "example" }, "stockEffect": { "field": "example", "label": "example", "direction": "up" } } ], "expressionContext": "example", "apiDelayMs": 1, "systemExcludedFields": [ "example" ], "dateFormat": "DMY", "timezone": "example" }, "fields": { "additionalProperty": [ { "apiName": "example", "description": "example", "format": "example", "examples": [ "example" ], "aliases": [ "example" ], "excludeFromAi": true, "derived": true, "defaultMapping": { "mode": "column", "source": "example", "staticValue": "example", "staticPickedIn": { "connection": "example", "module": "example", "id": "example", "name": "example" }, "transform": "example", "skip": true, "searchField": "example", "searchMethod": "example", "searchExpression": "example", "patch": { "when": [ "pending" ], "overwrite": "always" }, "files": { "sheet": "example", "holds": "name", "separator": "example" }, "key": true, "keyMethod": "example", "keyExpression": "example", "onNone": "empty", "onSeveral": "ask" }, "excluded": true, "requiredForImports": "waivable", "writtenAs": "upper", "mustBe": { "rule": "example", "says": "example" } } ] }, "libraries": [ { "manifest": { "namespace": "example", "version": "example", "scope": "global", "description": "example", "functions": [ { "name": "example", "description": "example", "params": [ { "name": "example", "type": "example", "optional": true, "description": "example" } ], "returns": "example", "examples": [ { "call": "example", "result": "example" } ], "tags": [ "example" ] } ] }, "source": "example" } ], "templates": [ { "name": "example", "description": "example", "config": { "additionalProperty": "example" } } ], "projects": [ { "name": "example", "description": "example", "config": { "additionalProperty": "example" } } ] }'Applies a whole configuration repository in one call — registry, annotations, settings, helper libraries and seeded templates. This is what the SDK’s push sends.
The registry and annotations are ONE connection’s: the one ?connector= names, which a push must (400 CONNECTION_REQUIRED otherwise). The libraries, the organisation settings and the templates are the organisation’s, and a pushed template names no connection: it is picked for on Target when it is used.
A bundle’s templates belong to the whole organisation, so pushing them is sharing: a plan without shared templates is refused rather than silently importing them as private.
Its helper libraries are each compiled and loaded against their manifests before anything is written, and published as a new version only when one differs from what the organisation already has — so a push that sends the same libraries every time makes no versions and moves the configuration’s version no further for them. The registry and each module’s annotations are compared the same way (#1589): only a part that differs from what the connection holds is written, and only a part written moves the version — so a push of what is already there moves it not at all, and under If-Match answers the version it was sent. A library the push makes is the repository’s (managedBy: sdk), read only on its page; one taken over in the browser is left as it is, and warnings says so (libraries/<name>: taken over in the browser…). Publishing libraries is the helper_libraries plan feature.
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.
Query Parameters
Section titled “Query Parameters”The connection this is about, by id: one of the organisation’s, or your own. REQUIRED: absent or empty is 400 CONNECTION_REQUIRED, listing the connections this bearer may name, because nothing picks one for a request that does not say (design §14.8). Any other — another organisation’s, or another person’s — is 404 CONNECTION_NOT_FOUND.
Example
con_8f2aThe connection this is about, by id: one of the organisation’s, or your own. REQUIRED: absent or empty is 400 CONNECTION_REQUIRED, listing the connections this bearer may name, because nothing picks one for a request that does not say (design §14.8). Any other — another organisation’s, or another person’s — is 404 CONNECTION_NOT_FOUND.
Header Parameters
Section titled “Header Parameters”The registryVersion this change was made against, as "7" or 7 — a weak tag (W/"7") is refused, since If-Match uses strong comparison. Sent, the write is refused with 409 (code: REGISTRY_CONFLICT, the current version in the body) when the organisation has moved since, and otherwise answers the version it made: one past the version sent for a write made in one transaction, or the version sent itself for a request that asks for no change (an empty PATCH /config/writing), since it makes none. A bundle (POST /config/bundle) is several transactions and only its first waits on this version: it answers the version its own bumps took the organisation to — each part bumps only when it writes something, so a push of what is already there answers the version sent — and none — nor an etag — when another write landed between them; one landing after them, while its templates are saved, withholds the etag alone. Omitted, there is no condition, and * is no condition either — and a write with no condition answers no registryVersion (nor, from a bundle, an etag), since nothing says which version it was made from. A value that is neither is 400 (code: BAD_IF_MATCH) rather than ignored — a precondition silently dropped looks like conflict detection and is not.
Example
"7"The registryVersion this change was made against, as "7" or 7 — a weak tag (W/"7") is refused, since If-Match uses strong comparison. Sent, the write is refused with 409 (code: REGISTRY_CONFLICT, the current version in the body) when the organisation has moved since, and otherwise answers the version it made: one past the version sent for a write made in one transaction, or the version sent itself for a request that asks for no change (an empty PATCH /config/writing), since it makes none. A bundle (POST /config/bundle) is several transactions and only its first waits on this version: it answers the version its own bumps took the organisation to — each part bumps only when it writes something, so a push of what is already there answers the version sent — and none — nor an etag — when another write landed between them; one landing after them, while its templates are saved, withholds the etag alone. Omitted, there is no condition, and * is no condition either — and a write with no condition answers no registryVersion (nor, from a bundle, an etag), since nothing says which version it was made from. A value that is neither is 400 (code: BAD_IF_MATCH) rather than ignored — a precondition silently dropped looks like conflict detection and is not.
Request Bodyrequired
Section titled “Request Bodyrequired”object
object
object
object
seedMappings is no longer a module setting: a mapping a new import starts from belongs to the field it is about. Set defaultMapping on the field annotation — PATCH /orgs/{org}/config/fields/{module}/{apiName}, or fields/<module>.json in a configuration repository. Values already stored were moved by migration 0035.
One record as the CRM names it in words (“Sales Order”), which sentences say; singular is the identifier expressions use (“SalesOrder”). Read-only: discovery takes it from the CRM, so a pushed value is ignored. Absent until a discovery has read it, when a reader says singular.
object
object
The organisation’s IANA timezone, which helpers.today() answers in. Read-only: it is taken from the CRM at sign-in, so a pushed value is ignored.
object
object
object
object
object
object
object
object
object
object
object
object
object
object
Deprecated: the older name of templates, read as templates. A bundle may send one or the other, not both.
object
object
Responses
Section titled “Responses”Applied: what changed and, for a push sent with a version in If-Match, the registry version it produced with the resolved-config etag for that same state. Another write landing between the push’s own version bumps withholds both; one landing after the last of them — while the templates are saved, before the state is hashed — withholds only the etag. A push without If-Match answers neither.
object
The resolved configuration’s ETag for the state this push produced — only beside registryVersion, and only when no other write landed before it was taken. It is taken last, after the push’s templates are saved, so another write landing after the push’s last version bump — while the templates are saved, say — withholds this alone: registryVersion is still answered, since it names only the version you sent and this push’s own changes, and this would name the other write too.
The version this push’s own writes took the organisation to, to send as the next write’s If-Match. Only a push sent with a version in If-Match answers one, and only when no other write landed between the push’s own version bumps — the registry, each module’s annotations, the libraries, each of which bumps only when it writes something (#1589), so a push of what is already there answers the version it was sent: a bundle is several transactions, of which only the first can be made on the version sent, and a version with somebody else’s change inside it would label a change you were never shown. A write landing after the last of them — while the templates, which move no version, are saved — is not inside this number: it is still answered, with etag withheld, and a write sent under it is refused (409), since the organisation has moved past it. A push without one (no header, or *) answers neither this nor etag, since nothing says which version your picture was built from — read the configuration for a version to write against.
created: templates the push made. updated: existing templates it changed — their name, description, kind or recipe, or a connection it cleared (a pushed template names none) — and, conservatively, one whose write kept losing to other pushes and was made without its precondition, which is counted whether or not it differed. A template re-sent unchanged is neither.
object
What the push stored or left alone and has something to say about, one sentence each, starting with the part’s path in the bundle — present only when there is something. A library taken over in the browser is left as it is (libraries/<name>: taken over in the browser…), first. And a template enabling a module the connection has but does not offer once this push’s registry is applied — one the registry leaves out, or one gone from the CRM: the template is stored, and an import started from it parks that module’s setup until the module is offered again. A module the connection has never had is still refused (422 UNKNOWN_MODULES).
Example
{ "ok": true}The request — its body or its query — did not match the schema (issues carries the Zod issue list), or: The request named no connection (code: CONNECTION_REQUIRED, with connections: the ones this bearer may name). Nothing picks one for a request that does not say (design §14.8).
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 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 plan cannot share templates (code: FEATURE_SHARED_TEMPLATES) or publish helper libraries (code: FEATURE_HELPER_LIBRARIES, for a bundle carrying any), the role is too low, or the organisation is closed (code: ORG_CLOSED). An organisation closed during the push is found when a new template is written, after the registry, the annotations, the libraries and any earlier templates committed: written says which. 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
ORG_CLOSED only, when the organisation closed among the push’s templates: what had committed before it, which the organisation’s change log records. Absent when it was closed before the push began, and on every other refusal.
object
The modules whose annotations landed before the push stopped.
Whether the bundle’s libraries were applied.
The templates saved before the push stopped, by name.
Examplegenerated
{ "error": "example", "code": "example", "written": { "registry": true, "annotations": [ "example" ], "libraries": true, "templates": [ "example" ] }}?connector= names a connection this person may not use: another organisation’s, or another person’s (code: CONNECTION_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"}Or a bound on what an organisation’s libraries hold is met, the same on every plan (holding says where it stands with the caps, proposed what this would have brought it to): LIBRARY_LIMIT — it would hold more than 20 libraries; LIBRARIES_TOO_LARGE — its libraries would come to more than 1 MB of source; LIBRARY_HISTORY_FULL — the versions it keeps would come to more than 25 MB; LIBRARY_PUBLISH_RATE — more than 50 versions in 24 hours, counted from the first of them. A publish that changes nothing makes no version and meets none of them. Checked before the push writes anything, where it is refused whole with nothing written and no written in the body. Where the bound is met only while the push is applied (a publish from a library’s page landed in between), its libraries are refused together in their own transaction and written says what had been written by then: the registry and the annotations it names, which stay. The organisation’s configuration has changed since the version in If-Match (code: REGISTRY_CONFLICT, the current version in the body), and nothing was written. Or another change overtook the push part way (code: PUSH_OVERTAKEN): a module’s fields changed while it was applied, typically a removed module taking its field rows, or discovery changing a field’s kind to one that takes no case the push gave it. The push stopped there. written says what had committed, the organisation’s change log records it, and no version is answered, since the push was not alone. Push again: what landed is written again to the same effect, and a field gone for good is then refused up front, by name.
object
object
What of this push was written before it stopped, and what was not.
object
The modules whose annotations landed before the push stopped.
Whether the bundle’s libraries were applied.
The templates saved before the push stopped, by name.
The module whose annotations were refused.
The fields the module had stopped having, when that was the change.
The fields whose kind changed to one that takes no case the push gave them, when that was the change (#553).
object
The field’s kind, as discovery last read it.
The cases this kind takes: none for a website, lower for an email.
object
The library that met the bound. Null where a push of several was refused in its own transaction and which of them met it cannot be told.
The organisation as it stands: what the list shows.
object
Libraries the organisation holds.
UTF-8 bytes of source across its libraries as they currently are.
UTF-8 bytes of source across every version it keeps. Removing a library removes its versions.
Versions published in the last 24 hours, across its libraries.
When the oldest of those leaves the 24 hours, so another may be published where the day’s cap is met. Null with none.
The most of each, the same on every plan.
object
What the publish, or the whole push it is part of, would have brought the organisation to: the figure that is past its bound.
object
Only where the cap was met WHILE the push was applied (a publish from a library’s page landed between its check and its libraries): what had been written by then, which stays. Absent, nothing was.
object
The modules whose annotations landed before the push stopped.
Whether the bundle’s libraries were applied.
The templates saved before the push stopped, by name.
Example
{ "code": "REGISTRY_CONFLICT"}The bundle gives a field a case its kind does not take (code: WRITTEN_AS_NOT_FOR_KIND, each named in fields) or a Must be rule that reaches past the value (code: INVALID_RULE, each named in fields with why), has a template enabling a subform (code: MODULE_IS_SUBFORM, naming the template and each subform), names a module or field this organisation does not have (code: UNKNOWN_MODULES, UNKNOWN_FIELDS; a field the CRM no longer returns is one it has, kept on purpose, and its annotation is written), gives a default match rule or a template’s key a field the destination cannot match by (code: UNMATCHABLE_FIELD, each named in rules), or carries a helper library that cannot be published: global in scope (GLOBAL_LIBRARY), sent twice (DUPLICATE_LIBRARY), named core or after one of Sloose’s own helpers (RESERVED_NAMESPACE), or one that does not compile or load against its manifest (LIBRARY_DOES_NOT_LOAD, saying which and why) — each checked before the push writes anything, so nothing of it lands. A template enabling a module the connection has, but that this push leaves unoffered, is not refused: it is stored, and named in warnings. A push another write overtook — one that moved a module a template names — is checked again against the modules as its writes left them, and refused for a name none holds any longer: its registry, annotations and libraries are then applied, no template is (written says which parts committed, and the organisation’s change log records them), and a push made again completes.
object
UNKNOWN_MODULES only: the template that names a module none holds.
UNKNOWN_MODULES only: the modules no one holds.
MODULE_IS_SUBFORM only: each subform the template enables, named in template.
UNKNOWN_MODULES only, refused after the push’s writes: what had committed before it. Absent for a refusal before any write.
object
The modules whose annotations landed before the push stopped.
Whether the bundle’s libraries were applied.
The templates saved before the push stopped, by name.
WRITTEN_AS_NOT_FOR_KIND: each field given a case its kind does not take. INVALID_RULE: each field given a Must be rule that reaches past the value, and why.
object
The field’s kind, as discovery last read it.
The cases this kind takes: none for a website, lower for an email.
object
What the rule reaches that it may not, in words.
UNMATCHABLE_FIELD only: each default match rule or template key that looks in a field the destination does not take with the method it asks, and why.
object
In words: the field cannot be matched with this method, and why.
Example
{ "fields": [ { "writtenAs": "upper", "takes": [ "upper" ] } ]}A helper library in the bundle could not be checked: the sandbox did not answer (code: SANDBOX_UNAVAILABLE). Nothing was written. Or the restore switch is on (code: MAINTENANCE): every route but /health and /robots.txt is refused before anything is read, with Retry-After (the operator’s ADMIN_TOKEN alone is let through to POST /staff/people/{id}/delete, and to nothing else).
Headers
Section titled “Headers”Seconds until asking again is worth it (300 while the switch is on).