{"swagger":"2.0","info":{"title":"BC Object Registry","version":"1.0.0","description":"Track Business Central object ID ranges for PTE and AppSource apps, and issue new collision-free ranges from Business Central, VS Code, scripts, CI or Copilot Studio.\n\nAuthenticate with an API key from the portal (API keys) in the X-API-Key header, or Authorization: Bearer <key>. Keys have scopes: read, allocate, write. Errors use RFC 9457 problem+json. Requests are rate limited per key by plan (X-RateLimit-* headers). Send Idempotency-Key on POSTs that create things.","contact":{"name":"OnlyBCFans","email":"info@onlybcfans.com"}},"host":"bcregistry.ai","basePath":"/api/v1","schemes":["https"],"consumes":["application/json"],"produces":["application/json"],"securityDefinitions":{"ApiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"An API key from the portal (API keys)."}},"security":[{"ApiKey":[]}],"tags":[{"name":"Apps","description":"The registry: apps and their object ranges."},{"name":"Ranges","description":"Issue new ranges and check proposed ones."},{"name":"Pools","description":"Windows that ranges are issued from, and their free ranges."},{"name":"Tenants","description":"Business Central tenants and their environments."},{"name":"Import","description":"Bulk import of existing apps."},{"name":"Workspace","description":"The workspace behind the API key."}],"paths":{"/apps":{"get":{"operationId":"ListApps","summary":"List apps","description":"Apps in the registry with their ranges, environments and overlaps. Filter by tenant, type, status, App ID or text. Scope: read.","tags":["Apps"],"x-ms-visibility":"important","consumes":[],"produces":["application/json"],"parameters":[{"name":"tenantId","in":"query","required":false,"description":"Our id for the tenant.","x-ms-summary":"tenantId","type":"string","format":"uuid"},{"name":"bcTenantId","in":"query","required":false,"description":"The Business Central (Microsoft Entra) tenant ID. From AL: TenantId().","x-ms-summary":"bcTenantId","type":"string","format":"uuid"},{"name":"type","in":"query","required":false,"description":"PTE or AppSource.","x-ms-summary":"type","type":"string","enum":["PTE","AppSource"]},{"name":"status","in":"query","required":false,"description":"Pending, Active or Retired.","x-ms-summary":"status","type":"string","enum":["Pending","Active","Retired"]},{"name":"appId","in":"query","required":false,"description":"The id in app.json.","x-ms-summary":"appId","type":"string","format":"uuid"},{"name":"q","in":"query","required":false,"description":"Text in the name, App ID, repo, publisher or ranges.","x-ms-summary":"q","type":"string"}],"responses":{"200":{"description":"The apps.","schema":{"$ref":"#/definitions/AppList"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"read\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}},"post":{"operationId":"CreateApp","summary":"Register an app","description":"Add an app that already has its object range(s), e.g. from app.json in a CI step. Overlaps are allowed and returned as warnings. Scope: write.","tags":["Apps"],"x-ms-visibility":"important","consumes":["application/json"],"produces":["application/json"],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string (e.g. a UUID). Retrying with the same key returns the first response instead of doing it twice.","x-ms-summary":"Idempotency-Key","type":"string"},{"name":"body","in":"body","required":true,"description":"The app.","schema":{"$ref":"#/definitions/AppInput"}}],"responses":{"201":{"description":"The new app and any warnings.","schema":{"$ref":"#/definitions/AppResult"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"write\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}}},"/apps/{id}":{"get":{"operationId":"GetApp","summary":"Get an app","description":"One app with ranges, environments and overlaps. Scope: read.","tags":["Apps"],"x-ms-visibility":"important","consumes":[],"produces":["application/json"],"parameters":[{"name":"id","in":"path","required":true,"description":"The app's id.","x-ms-summary":"id","type":"string"}],"responses":{"200":{"description":"The app.","schema":{"$ref":"#/definitions/AppResult"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"read\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}},"patch":{"operationId":"UpdateApp","summary":"Update an app","description":"Change only the fields sent, e.g. set the App ID and mark the app Active, or retire it. Scope: write.","tags":["Apps"],"x-ms-visibility":"important","consumes":["application/json"],"produces":["application/json"],"parameters":[{"name":"id","in":"path","required":true,"description":"The app's id.","x-ms-summary":"id","type":"string"},{"name":"body","in":"body","required":true,"description":"Fields to change.","schema":{"$ref":"#/definitions/AppPatch"}}],"responses":{"200":{"description":"The updated app.","schema":{"$ref":"#/definitions/AppResult"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"write\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}},"delete":{"operationId":"DeleteApp","summary":"Delete an app","description":"Delete an app and free its ranges. Confirm with the app's exact name, like the portal's typed confirmation. Org admins can restore it for 30 days. Scope: write.","tags":["Apps"],"x-ms-visibility":"advanced","consumes":[],"produces":["application/json"],"parameters":[{"name":"id","in":"path","required":true,"description":"The app's id.","x-ms-summary":"id","type":"string"},{"name":"confirm","in":"query","required":true,"description":"The app's exact name.","x-ms-summary":"confirm","type":"string"}],"responses":{"200":{"description":"What was deleted.","schema":{"$ref":"#/definitions/DeleteResult"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"write\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}}},"/ranges/allocate":{"post":{"operationId":"AllocateRange","summary":"Issue a new range","description":"Reserve the first free block of the size asked for and save it as a Pending app. Collisions are checked across the whole tenant. Send an Idempotency-Key so retries never issue twice. Scope: allocate.","tags":["Ranges"],"x-ms-visibility":"important","consumes":["application/json"],"produces":["application/json"],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string (e.g. a UUID). Retrying with the same key returns the first response instead of doing it twice.","x-ms-summary":"Idempotency-Key","type":"string"},{"name":"body","in":"body","required":true,"description":"What to issue.","schema":{"$ref":"#/definitions/AllocateInput"}}],"responses":{"201":{"description":"The issued range, ready for app.json.","schema":{"$ref":"#/definitions/AllocateResult"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"allocate\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}}},"/ranges/check":{"post":{"operationId":"CheckRange","summary":"Check a range","description":"Is from–to free in the tenant (or AppSource registry)? Lists the apps it would overlap. Scope: read.","tags":["Ranges"],"x-ms-visibility":"important","consumes":["application/json"],"produces":["application/json"],"parameters":[{"name":"body","in":"body","required":true,"description":"The range to check.","schema":{"$ref":"#/definitions/CheckInput"}}],"responses":{"200":{"description":"Whether it's free, and any overlaps.","schema":{"$ref":"#/definitions/CheckResult"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"read\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}}},"/pools":{"get":{"operationId":"ListPools","summary":"List pools","description":"Each tenant's PTE pool and the partner-wide AppSource pools, with usage. Scope: read.","tags":["Pools"],"x-ms-visibility":"important","consumes":[],"produces":["application/json"],"parameters":[],"responses":{"200":{"description":"The pools.","schema":{"$ref":"#/definitions/PoolList"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"read\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}}},"/pools/{id}/free":{"get":{"operationId":"GetFreeRanges","summary":"Free ranges in a pool","description":"The pool's free ranges, computed live. Scope: read.","tags":["Pools"],"x-ms-visibility":"important","consumes":[],"produces":["application/json"],"parameters":[{"name":"id","in":"path","required":true,"description":"The pool's id.","x-ms-summary":"id","type":"string"}],"responses":{"200":{"description":"Free ranges.","schema":{"$ref":"#/definitions/FreeRanges"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"read\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}}},"/tenants":{"get":{"operationId":"ListTenants","summary":"List tenants","description":"The workspace's Business Central tenants with their environments. Scope: read.","tags":["Tenants"],"x-ms-visibility":"important","consumes":[],"produces":["application/json"],"parameters":[],"responses":{"200":{"description":"The tenants.","schema":{"$ref":"#/definitions/TenantList"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"read\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}},"post":{"operationId":"CreateTenant","summary":"Add a tenant","description":"Add a customer tenant (Premium (Partner)). It gets its own PTE pool and a Production environment. Scope: write.","tags":["Tenants"],"x-ms-visibility":"advanced","consumes":["application/json"],"produces":["application/json"],"parameters":[{"name":"body","in":"body","required":true,"description":"The tenant.","schema":{"$ref":"#/definitions/TenantInput"}}],"responses":{"201":{"description":"The new tenant.","schema":{"$ref":"#/definitions/TenantResult"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"write\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}}},"/tenants/{id}":{"get":{"operationId":"GetTenant","summary":"Get a tenant","description":"One tenant, by our id or its BC Tenant ID. Scope: read.","tags":["Tenants"],"x-ms-visibility":"important","consumes":[],"produces":["application/json"],"parameters":[{"name":"id","in":"path","required":true,"description":"The tenant's id.","x-ms-summary":"id","type":"string"}],"responses":{"200":{"description":"The tenant.","schema":{"$ref":"#/definitions/TenantResult"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"read\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}},"patch":{"operationId":"UpdateTenant","summary":"Update a tenant","description":"Rename it, change its domain or Tenant ID, or activate/deactivate it. Scope: write.","tags":["Tenants"],"x-ms-visibility":"advanced","consumes":["application/json"],"produces":["application/json"],"parameters":[{"name":"id","in":"path","required":true,"description":"The tenant's id.","x-ms-summary":"id","type":"string"},{"name":"body","in":"body","required":true,"description":"Fields to change.","schema":{"$ref":"#/definitions/TenantPatch"}}],"responses":{"200":{"description":"The tenant.","schema":{"$ref":"#/definitions/TenantResult"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"write\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}}},"/import":{"post":{"operationId":"ImportApps","summary":"Import existing apps","description":"Bulk import from a JSON array or a file (registry.json, ObjectRegistry.md, app.json, CSV, .zip). dryRun (default) returns the preview and a previewId; commit with dryRun false and that previewId. Scope: write.","tags":["Import"],"x-ms-visibility":"advanced","consumes":["application/json"],"produces":["application/json"],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string (e.g. a UUID). Retrying with the same key returns the first response instead of doing it twice.","x-ms-summary":"Idempotency-Key","type":"string"},{"name":"body","in":"body","required":true,"description":"Apps or a file.","schema":{"$ref":"#/definitions/ImportInput"}}],"responses":{"200":{"description":"The preview report, and what was committed.","schema":{"$ref":"#/definitions/ImportReport"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"write\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}}},"/import/{id}":{"get":{"operationId":"GetImport","summary":"Get an import","description":"An import job's status and counts. Scope: write.","tags":["Import"],"x-ms-visibility":"advanced","consumes":[],"produces":["application/json"],"parameters":[{"name":"id","in":"path","required":true,"description":"The import's id.","x-ms-summary":"id","type":"string"}],"responses":{"200":{"description":"The import job.","schema":{"$ref":"#/definitions/ImportJob"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"write\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}}},"/import/{id}/undo":{"post":{"operationId":"UndoImport","summary":"Undo an import","description":"Undo a committed import within 24 hours, if none of its apps were edited since. Scope: write.","tags":["Import"],"x-ms-visibility":"advanced","consumes":[],"produces":["application/json"],"parameters":[{"name":"id","in":"path","required":true,"description":"The import's id.","x-ms-summary":"id","type":"string"}],"responses":{"200":{"description":"What was undone.","schema":{"$ref":"#/definitions/UndoResult"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"write\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}}},"/me":{"get":{"operationId":"GetWorkspace","summary":"Who am I","description":"The workspace, plan and scopes this API key acts with. Scope: read.","tags":["Workspace"],"x-ms-visibility":"important","consumes":[],"produces":["application/json"],"parameters":[],"responses":{"200":{"description":"The workspace and key.","schema":{"$ref":"#/definitions/Me"}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The key lacks the \"read\" scope."},"404":{"description":"Not found."},"422":{"description":"The request was refused; see detail."},"429":{"description":"Rate limit exceeded; see Retry-After."},"default":{"description":"Error (problem+json).","schema":{"$ref":"#/definitions/Problem"}}}}}},"definitions":{"Range":{"type":"object","required":["from","to"],"properties":{"from":{"type":"integer","example":50100},"to":{"type":"integer","example":50119}}},"TenantRef":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"bcTenantId":{"type":"string","format":"uuid"},"customerName":{"type":"string"}}},"App":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Warehouse Labels"},"appId":{"type":"string","format":"uuid","description":"The id in app.json; empty while Pending.","x-nullable":true},"type":{"type":"string","enum":["PTE","AppSource"]},"status":{"type":"string","enum":["Pending","Active","Retired"]},"tenant":{"$ref":"#/definitions/TenantRef"},"ranges":{"type":"array","items":{"$ref":"#/definitions/Range"}},"rangesText":{"type":"string","example":"50100–50119; 50200–50209"},"environments":{"type":"array","items":{"type":"string"},"description":"BC environments the app is deployed to."},"publisher":{"type":"string"},"repo":{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string"},"visibility":{"type":"string","enum":["Public","Private"]}}},"issuedOn":{"type":"string","format":"date"},"overlapsWith":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}}},"notes":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"AppList":{"type":"object","properties":{"apps":{"type":"array","items":{"$ref":"#/definitions/App"}},"count":{"type":"integer"}}},"AppResult":{"type":"object","properties":{"app":{"$ref":"#/definitions/App"},"warnings":{"type":"array","items":{"type":"string"}}}},"AppInput":{"type":"object","required":["name","ranges"],"properties":{"name":{"type":"string"},"type":{"type":"string","enum":["PTE","AppSource"],"default":"PTE"},"tenantId":{"type":"string","format":"uuid"},"bcTenantId":{"type":"string","format":"uuid","description":"Name the tenant by its BC Tenant ID instead of tenantId."},"appId":{"type":"string","format":"uuid","description":"The id in app.json. Required for Active."},"ranges":{"type":"array","items":{"$ref":"#/definitions/Range"},"description":"The app's object ranges. A string such as \"50100-50119; 50200-50209\" is accepted too."},"status":{"type":"string","enum":["Pending","Active","Retired"]},"publisher":{"type":"string"},"repoName":{"type":"string"},"repoUrl":{"type":"string"},"repoVisibility":{"type":"string","enum":["Public","Private"]},"notes":{"type":"string"},"environments":{"type":"array","items":{"type":"string"},"description":"BC environment names, case-insensitive."}}},"AppPatch":{"type":"object","description":"Send only the fields to change.","properties":{"name":{"type":"string"},"appId":{"type":"string","format":"uuid"},"ranges":{"type":"array","items":{"$ref":"#/definitions/Range"}},"status":{"type":"string","enum":["Pending","Active","Retired"]},"publisher":{"type":"string"},"repoName":{"type":"string"},"repoUrl":{"type":"string"},"repoVisibility":{"type":"string","enum":["Public","Private"]},"notes":{"type":"string"},"environments":{"type":"array","items":{"type":"string"}}}},"DeleteResult":{"type":"object","properties":{"deleted":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"freed":{"type":"string"}}},"restorableDays":{"type":"integer"}}},"AllocateInput":{"type":"object","required":["name","size"],"properties":{"name":{"type":"string","description":"A project name; saved as a Pending app.","example":"Contoso Labels"},"size":{"type":"integer","description":"How many object IDs.","example":20},"type":{"type":"string","enum":["PTE","AppSource"],"default":"PTE"},"tenantId":{"type":"string","format":"uuid"},"bcTenantId":{"type":"string","format":"uuid","description":"From AL: TenantId(). Optional on single-tenant plans."},"poolId":{"type":"string","format":"uuid","description":"A specific pool (e.g. one of several AppSource pools)."},"environments":{"type":"array","items":{"type":"string"},"description":"BC environment names the app will be deployed to."}}},"AllocateResult":{"type":"object","properties":{"range":{"$ref":"#/definitions/Range"},"rangeText":{"type":"string","example":"50120–50139"},"idRanges":{"type":"array","items":{"$ref":"#/definitions/Range"},"description":"Ready for app.json."},"app":{"$ref":"#/definitions/App"}}},"CheckInput":{"type":"object","required":["from","to"],"properties":{"from":{"type":"integer"},"to":{"type":"integer"},"type":{"type":"string","enum":["PTE","AppSource"]},"tenantId":{"type":"string","format":"uuid"},"bcTenantId":{"type":"string","format":"uuid"}}},"CheckResult":{"type":"object","properties":{"range":{"$ref":"#/definitions/Range"},"rangeText":{"type":"string"},"free":{"type":"boolean","description":"True when no app in the tenant (or AppSource registry) uses any of these IDs."},"overlaps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"ranges":{"type":"array","items":{"$ref":"#/definitions/Range"}}}}},"pool":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"from":{"type":"integer"},"to":{"type":"integer"}}},"tenant":{"$ref":"#/definitions/TenantRef"}}},"Pool":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":"string","enum":["PTE","AppSource"]},"from":{"type":"integer"},"to":{"type":"integer"},"tenant":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customerName":{"type":"string"},"active":{"type":"boolean"}}},"apps":{"type":"integer"},"usedIds":{"type":"integer"},"freeIds":{"type":"integer"}}},"PoolList":{"type":"object","properties":{"pools":{"type":"array","items":{"$ref":"#/definitions/Pool"}}}},"FreeRanges":{"type":"object","properties":{"pool":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":"string"},"from":{"type":"integer"},"to":{"type":"integer"}}},"free":{"type":"array","items":{"$ref":"#/definitions/Range"}},"freeText":{"type":"string"},"freeIds":{"type":"integer"}}},"Tenant":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"hosting":{"type":"string","enum":["online","onprem"],"description":"onprem: no Tenant ID and no admin center; address it by id."},"bcTenantId":{"type":"string","format":"uuid","description":"Null for on-premises tenants.","x-nullable":true},"customerName":{"type":"string"},"domain":{"type":"string"},"active":{"type":"boolean"},"adminCenterUrl":{"type":"string","description":"Null for on-premises tenants.","x-nullable":true},"environments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":"string","enum":["Production","Sandbox"]}}}}}},"TenantList":{"type":"object","properties":{"tenants":{"type":"array","items":{"$ref":"#/definitions/Tenant"}}}},"TenantResult":{"type":"object","properties":{"tenant":{"$ref":"#/definitions/Tenant"}}},"TenantInput":{"type":"object","required":["customerName"],"properties":{"hosting":{"type":"string","enum":["online","onprem"],"default":"online"},"bcTenantId":{"type":"string","description":"Required for online tenants; omit for on-premises."},"customerName":{"type":"string"},"domain":{"type":"string"}}},"TenantPatch":{"type":"object","properties":{"customerName":{"type":"string"},"domain":{"type":"string"},"bcTenantId":{"type":"string"},"hosting":{"type":"string","enum":["online","onprem"]},"active":{"type":"boolean"}}},"ImportInput":{"type":"object","properties":{"dryRun":{"type":"boolean","default":true,"description":"Preview only (default). Commit with dryRun false and the previewId."},"previewId":{"type":"string","format":"uuid","description":"Commit this previewed import exactly as previewed."},"decisions":{"type":"object","additionalProperties":{"type":"string","enum":["skip","update","new"]},"description":"Per row index; duplicates default to skip."},"tenantId":{"type":"string","format":"uuid"},"bcTenantId":{"type":"string","format":"uuid"},"apps":{"type":"array","items":{"$ref":"#/definitions/AppInput"}},"file":{"type":"object","properties":{"name":{"type":"string","example":"registry.json"},"content":{"type":"string"},"encoding":{"type":"string","enum":["utf8","base64"],"default":"utf8"}},"description":"registry.json, ObjectRegistry.md, app.json, CSV, or a base64 .zip of repos."}}},"ImportReport":{"type":"object","properties":{"dryRun":{"type":"boolean"},"previewId":{"type":"string","format":"uuid"},"counts":{"type":"object","properties":{"new":{"type":"integer"},"duplicate":{"type":"integer"},"invalid":{"type":"integer"},"overLimit":{"type":"integer"},"overlapping":{"type":"integer"}}},"rows":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"source":{"type":"string"},"name":{"type":"string"},"appId":{"type":"string"},"outcome":{"type":"string","enum":["new","duplicate","invalid","over-limit"]},"reason":{"type":"string"},"decision":{"type":"string"},"overlaps":{"type":"array","items":{"type":"string"}},"warnings":{"type":"array","items":{"type":"string"}}}}},"committed":{"type":"object","properties":{"created":{"type":"integer"},"updated":{"type":"integer"},"skipped":{"type":"integer"}}}}},"ImportJob":{"type":"object","properties":{"import":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["previewed","committed","undone"]},"source":{"type":"string"},"fileName":{"type":"string"},"format":{"type":"string"},"createdAt":{"type":"string"},"committedAt":{"type":"string"}}}}},"UndoResult":{"type":"object","properties":{"undone":{"type":"object","properties":{"removed":{"type":"integer"},"restored":{"type":"integer"}}}}},"Me":{"type":"object","properties":{"workspace":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"string"},"multiTenant":{"type":"boolean"}}},"plan":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"maxTenants":{"type":"integer"},"maxPteApps":{"type":"integer"},"requestsPerMinute":{"type":"integer"}}},"key":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"scopes":{"type":"array","items":{"type":"string"}},"role":{"type":"string"}}}}},"Problem":{"type":"object","description":"RFC 9457 problem details.","properties":{"type":{"type":"string"},"title":{"type":"string","example":"Tenant required"},"status":{"type":"integer"},"detail":{"type":"string"},"errors":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}}}}}}}}