{"info":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","description":"<html><head></head><body><p><strong>Direct Send policy, 25 October 2026:</strong> This collection has no executable pre-request or test scripts. Pressing Send reaches the configured API endpoint; the server returns its validation or authorization response. Fill required variables and file paths yourself. Older mentions below of Postman confirmation guards, automatic fixture generation, or scripted assertions are superseded. Check the effect label before sending and never blindly retry an uncertain write.</p>\n<h1 id=\"ai-zeny-api-local-cloud\">AI Zeny API (Local + Cloud)</h1>\n<p><strong>Start here.</strong> One collection, three top-level paths:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Folder</th>\n<th>Where the request runs</th>\n<th>Base URL</th>\n<th>Bearer token</th>\n<th>PC online?</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>Local PC (localhost / LAN)</strong></td>\n<td>Directly on the Windows PC</td>\n<td><code>{{baseUrl}}</code> (or its LAN address)</td>\n<td><code>{{localApiToken}}</code></td>\n<td>Yes</td>\n</tr>\n<tr>\n<td><strong>Cloud Relay (online PC via Pusher)</strong></td>\n<td>Cloud forwards a supported operation to the PC</td>\n<td><code>{{cloudBaseUrl}}</code></td>\n<td><code>{{cloudApiToken}}</code></td>\n<td>Yes</td>\n</tr>\n<tr>\n<td><strong>Cloud Snapshot (server SQLite; PC may be offline)</strong></td>\n<td>Cloud reads its latest available SQLite snapshot</td>\n<td><code>{{cloudBaseUrl}}</code></td>\n<td><code>{{cloudApiToken}}</code></td>\n<td>No</td>\n</tr>\n</tbody>\n</table>\n</div><p>Choose the path by <strong>data source</strong>, not just HTTP method. Local and Relay can contain POST requests that only read data; <em>(read only)</em> folders do not change BUSY. <strong>⚠</strong> folders contain actions that can change BUSY or AI Zeny settings and require the one-send <code>confirmMutating=yes</code> guard. Voucher <strong>Create</strong> (write) and Voucher <strong>PDFs</strong> (read/print an existing voucher) are separate. Do not automatically retry a write whose outcome is uncertain. Snapshot contains GET requests only and reports its data freshness; an offline PC does not make a snapshot fresher.</p>\n<p>The Local PC path is served by the <strong>AI Zeny Host</strong> Windows service. Local requests use one Local Bearer token except public health; Cloud Relay and Cloud Snapshot use the organization's cloud API token. Never interchange those tokens. The collection contains request definitions, not token values. Select a private Postman environment such as <strong>AI Zeny – Development</strong>; do not share that environment or export its synced secrets to customers. Give customers a separate environment with their own token values.</p>\n<p>Source contracts: the Windows Local API documentation and routes, plus the cloud V1 Relay catalogue and Snapshot registry. Keep this collection aligned with them whenever operations, parameters, responses or examples change.</p>\n<h2 id=\"before-you-start\">Before you start</h2>\n<ol>\n<li><p>The API runs inside the <strong>AI Zeny Host</strong> Windows service. It starts with Windows and the <strong>AI Zeny Recovery</strong> service restarts it by itself if it stops (D42) — no command is needed. If <code>/api/v1/health</code> does not answer: wait a minute (AI Zeny may be updating or restarting); if the AI Zeny window says <strong>Local API stopped</strong>, someone stopped it on purpose — press <strong>Start API</strong> there. Otherwise check that <code>baseUrl</code> has the right port.</p>\n</li>\n<li><p>Select the environment <strong>AI Zeny – Development</strong>. <code>baseUrl</code> is <code>http://127.0.0.1:8801</code> (8801 is the default port; the real port is in <code>%ProgramData%\\AI Zeny\\local-api.endpoint.json</code>). From another computer on the same LAN, set <code>baseUrl</code> to that PC's LAN address and Local API port, as shown in AI Zeny.</p>\n</li>\n<li><p>Put the Local PC token into <strong><code>localApiToken</code></strong> in a private environment. Prefer a local/current-only value; the existing Development environment has a synced secret value, so do not share or export that environment. Get it in AI Zeny: <em>BUSY Data → Local API → Local API Bearer Token → Reveal / Copy token</em> (the GUI must be unlocked with your PIN). The file <code>%ProgramData%\\AI Zeny\\local-api.token</code> holds it too (readable by the nominated Windows user only).</p>\n</li>\n<li><p>Run <strong>Local PC → Health &amp; Status (read only) → Health (public)</strong> first, then <strong>Status</strong>. If Status answers 200, the token and connection are correct.</p>\n</li>\n</ol>\n<h2 id=\"response-envelope-every-response-since-007\">Response envelope (every response, since 0.0.7)</h2>\n<p>Every JSON response has three top-level members, in this order — plus, on a few successes only, one optional fourth and last member <code>configuration</code> (AI Zeny's own saved settings for that data, for example on <strong>List BUSY companies</strong>; never on a failure or an NDJSON line):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{ \"success\": true, \"data\": [], \"metadata\": {} }\n\n</code></pre>\n<ul>\n<li><p><code>success</code> — a boolean: <code>true</code> only when the request was accepted, validated and completed. An empty result is still <code>true</code> (<code>\"data\": []</code>).</p>\n</li>\n<li><p><code>data</code> — only the requested data: a list directly as an array (companies, units), one record as an object, <code>null</code> on failure.</p>\n</li>\n<li><p><code>metadata</code> — never null (<code>{}</code> when empty): pagination, filters, timing (<code>elapsedMs</code>), <code>apiVersion</code>, <code>operation</code>, <code>requestId</code>, plan limits, or the error.</p>\n</li>\n</ul>\n<p>HTTP status codes stay meaningful (2xx / 4xx / 5xx). The collection-level test checks the envelope on every response (on an <code>application/x-ndjson</code> stream, on every line).</p>\n<h2 id=\"authentication\">Authentication</h2>\n<p>Local PC uses <code>Authorization: Bearer {{localApiToken}}</code> through collection-level auth. Cloud Relay and Cloud Snapshot use request-level Bearer <code>{{cloudApiToken}}</code>. <code>X-Api-Key</code>, Basic, sessions, cookies and query tokens are refused with <code>401 UNAUTHORIZED</code> and <code>WWW-Authenticate: Bearer</code>. The Local token is created on the PC and must not be sent as the Cloud token or placed in a URL.</p>\n<h2 id=\"network-rules\">Network rules</h2>\n<ul>\n<li><p>Accepted only from loopback or a private LAN address (10/8, 172.16/12, 192.168/16, 169.254/16, 100.64/10, fc00::/7, fe80::/10) and with a <code>Host</code> that names this PC; otherwise <code>403 LOCAL_NETWORK_ONLY</code>. Forwarded headers are never read.</p>\n</li>\n<li><p>Windows Firewall rule <em>AI Zeny Local API (local network)</em>: TCP on the Local API port, LocalSubnet, Domain/Private profiles only.</p>\n</li>\n<li><p>Bodies are JSON, at most 16 KiB (<code>413 REQUEST_TOO_LARGE</code>); schedule routes and the sales-order create accept 64 KiB, saved-query routes 128 KiB, script and message routes 1 MiB, and a message insert 9 MiB.</p>\n</li>\n<li><p>While the Host stops (for example during an automatic update) new requests get <code>503 HOST_STOPPING</code> with <code>Retry-After: 30</code>.</p>\n</li>\n<li><p>If the PC's user stopped the Local API in AI Zeny, the port is closed (connection refused) until they press <strong>Start API</strong>. Since D43 only the listener closes: the Host keeps running schedules, the cloud relay and enrollment refresh.</p>\n</li>\n</ul>\n<h2 id=\"errors\">Errors</h2>\n<p>Every error is the envelope with <code>\"success\": false</code>, <code>\"data\": null</code> and <code>metadata.error { code, message[, field] }</code>, plus <code>metadata.requestId</code> (the same id as the <code>X-Request-Id</code> header) and, on V1 data routes, <code>metadata.apiVersion</code>. <code>field</code> names the refused request member. Messages are fixed text: no SQL, paths, servers, passwords, tokens or data. Unknown routes: <code>404 NOT_FOUND</code>; a version that does not exist: <code>404 API_VERSION_UNSUPPORTED</code>.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{ \"success\": false, \"data\": null, \"metadata\": { \"error\": { \"code\": \"INVALID_PARAMETER\", \"message\": \"…\", \"field\": \"financialYear\" }, \"requestId\": \"…\", \"apiVersion\": \"v1\" } }\n\n</code></pre>\n<h2 id=\"environment-variables\">Environment variables</h2>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>baseUrl</code></td>\n<td>Local PC base URL, e.g. <code>http://127.0.0.1:8801</code> or the PC's LAN address and port</td>\n</tr>\n<tr>\n<td><code>localApiToken</code></td>\n<td>Local PC Bearer token. Keep its environment private; do not share or export its synced value</td>\n</tr>\n<tr>\n<td><code>companyCode</code></td>\n<td>A configured BUSY company code for the read-only V1 operations, e.g. <code>COMP0001</code> (<code>^[A-Z0-9_-]{1,32}$</code>)</td>\n</tr>\n<tr>\n<td><code>financialYear</code></td>\n<td>Four-digit starting year, e.g. <code>2026</code> = April 2026 – March 2027</td>\n</tr>\n<tr>\n<td><code>confirmMutating</code></td>\n<td>Leave empty. <code>yes</code> lets one mutating request run (reset automatically after it).</td>\n</tr>\n<tr>\n<td><code>targetCompanyCode</code></td>\n<td>The company a mutating BUSY company request acts on. Empty by default.</td>\n</tr>\n<tr>\n<td><code>masterAccountId</code></td>\n<td>Test account code set by create account; used by modify account. Leave empty until creation succeeds.</td>\n</tr>\n<tr>\n<td><code>masterAccountName</code></td>\n<td>Test account name set by create account; sent as <code>expectedName</code> by modify account.</td>\n</tr>\n<tr>\n<td><code>masterProductId</code></td>\n<td>Test product code set by create product; used by modify product. Leave empty until creation succeeds.</td>\n</tr>\n<tr>\n<td><code>masterProductName</code></td>\n<td>Test product name set by create product; sent as <code>expectedName</code> by modify product.</td>\n</tr>\n<tr>\n<td><code>busySqlPassword</code></td>\n<td>SQL login password for <em>create (SQL Server)</em> — <strong>current value only</strong>, clear it after use.</td>\n</tr>\n<tr>\n<td><code>scheduleName</code></td>\n<td>A schedule's name for the Schedules requests.</td>\n</tr>\n<tr>\n<td><code>scheduleScriptName</code></td>\n<td>The saved named script a new schedule runs (use a harmless one when testing).</td>\n</tr>\n<tr>\n<td><code>scheduleRevision</code></td>\n<td>The schedule revision you read (set by create and change).</td>\n</tr>\n<tr>\n<td><code>scheduleRunId</code></td>\n<td>A history row id (set by <em>Run history</em> and <em>Run now</em>).</td>\n</tr>\n<tr>\n<td><code>messageChannel</code></td>\n<td><code>email</code> or <code>whatsapp</code> (Messages requests; collection default <code>email</code>)</td>\n</tr>\n<tr>\n<td><code>messageId</code></td>\n<td>A message row id (set by <em>List messages</em> and <em>Insert</em>)</td>\n</tr>\n<tr>\n<td><code>messageRevision</code></td>\n<td>The row revision you read (set by list, get, insert, update, reconcile)</td>\n</tr>\n<tr>\n<td><code>cloudBaseUrl</code></td>\n<td><code>https://api.aizeny.com</code> for Cloud Relay and Cloud Snapshot</td>\n</tr>\n<tr>\n<td><code>cloudApiToken</code></td>\n<td>Organization cloud API token for Cloud Relay and Cloud Snapshot; keep private and never use the Local API token here</td>\n</tr>\n<tr>\n<td><code>salesOrderReference</code></td>\n<td>A new, unique test reference for <strong>⚠ Voucher Create</strong> (current value only; the request is skipped without one).</td>\n</tr>\n<tr>\n<td><code>salesOrderId</code></td>\n<td>Set by the sales-order create test.</td>\n</tr>\n<tr>\n<td><code>cloudIdempotencyKey</code></td>\n<td>Set and cleared by the Cloud master-write requests (one key per write; kept after a <code>504</code> so a retry reuses it).</td>\n</tr>\n<tr>\n<td><code>confirmHighImpact</code></td>\n<td>Leave empty. A <strong>⚠⚠</strong> request (uploads, Google writes, backup and restore, M-PIN recovery) runs only with <code>confirmMutating = yes</code> <strong>and</strong> this set to the exact route its pre-request script names; both are cleared after one send.</td>\n</tr>\n<tr>\n<td><code>sqlCompanyCode</code> / <code>sqlFinancialYear</code></td>\n<td>SQL Server test company COMP0002 / 2026 (the defaults of <code>companyCode</code> / <code>financialYear</code>).</td>\n</tr>\n<tr>\n<td><code>accessCompanyCode</code> / <code>accessFinancialYear</code> / <code>accessCustomerId</code> / <code>accessProductId</code> / <code>accessSalesInvoiceVoucherId</code> / <code>accessSalesInvoiceNumber</code></td>\n<td>Access test company COMP0001 / FY2026 and its fixtures: copy current values into <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code>, <code>productId</code>, <code>salesInvoiceVoucherId</code> to test Access. Bounded BUSY writes are supported on Access within each route's documented limits; the four account report-PDF routes still refuse Access with <code>409 BUSY_REPORT_PROVIDER_UNSUPPORTED</code>. Use fresh synthetic references for writes and check the route's prerequisites.</td>\n</tr>\n<tr>\n<td><code>salesInvoiceReference</code>, <code>receiptReference</code>, <code>returnReference</code>, <code>purchaseReference</code>, <code>purchaseReturnReference</code>, <code>paymentReference</code></td>\n<td>NEW unique test references for the ⚠ voucher creates (current values only).</td>\n</tr>\n<tr>\n<td><code>masterAccountGroupId</code> / <code>…Name</code>, <code>masterProductGroupId</code> / <code>…Name</code>, <code>lastContactId</code></td>\n<td>Set by the ⚠ group and contact create requests; used by their modify requests.</td>\n</tr>\n<tr>\n<td><code>savedQueryPin</code> / <code>savedQueryNewPin</code></td>\n<td>Secret, current value only: a saved query's source PIN (not the PC's M-PIN).</td>\n</tr>\n<tr>\n<td><code>catalogueTemplateName</code>, <code>catalogueNewDesignName</code>, <code>catalogueTemplateRevision</code>, <code>photoSourceFolder</code></td>\n<td>Catalogue design and photo-source requests.</td>\n</tr>\n<tr>\n<td><code>googleExportName</code> / <code>googleExportRevision</code>, <code>googleAttemptId</code>, <code>googleConnectionId</code>, <code>googleSpreadsheetId</code>, <code>googleSheetId</code></td>\n<td>Google requests (this PC only).</td>\n</tr>\n<tr>\n<td><code>backupDriveFileId</code>, <code>backupUploadId</code>, <code>backupRestoreId</code>, <code>backupRecoveryKey</code> (secret)</td>\n<td>Backup and restore requests (this PC only).</td>\n</tr>\n<tr>\n<td><code>recoveryChannel</code>, <code>recoveryCode</code> (secret), <code>recoveryNewMpin</code> (secret)</td>\n<td>M-PIN recovery requests (this PC only; a code is a real message).</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Not included (GUI-internal):</strong> <code>POST /api/v1/gui/presence</code>, <code>/enroll</code>, <code>/unlock/verify</code>, <code>/unlock/create</code>, <code>/unlock/change</code> — used only by the AI Zeny window. Every other Local API route has a request under <strong>Local PC</strong> (2026-10-18 acceptance audit): the management routes added that day are in the folders <em>Catalogue Designs &amp; Photo Sources</em>, <em>Upload, Google &amp; Backup Status</em>, and the ⚠ folders <em>Cloud Data Upload</em>, <em>Google</em>, <em>Backup &amp; Restore</em> and <em>Security &amp; Subscription</em>.</p>\n</body></html>","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","toc":[{"content":"AI Zeny API (Local + Cloud)","slug":"ai-zeny-api-local-cloud"}],"owner":"16351567","collectionId":"2c5e6107-2257-4357-9a20-49803c3534c5","publishedId":"2sBYHRVMN3","public":true,"customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"},"publishDate":"2026-10-14T06:49:27.000Z"},"item":[{"name":"Local PC (localhost / LAN)","item":[{"name":"Health & Status (read only)","item":[{"name":"Health (public)","id":"deb68ede-bf6e-73fb-e88c-15292d527061","request":{"auth":{"type":"noauth","isInherited":false},"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/health","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/health</code> · no token · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Run this first.</strong> Liveness of the AI Zeny Host. The only route that needs <strong>no token</strong>.</p>\n<p>Returns the Host version and uptime in seconds, nothing else (no tenant, enrollment, path or configuration detail).</p>\n<ul>\n<li><code>200</code> <code>{ \"success\": true, \"data\": { \"status\": \"ok\", \"version\": \"0.0.7\", \"uptimeSec\": 36971 }, \"metadata\": {} }</code></li>\n<li>No answer at all: AI Zeny may be starting, updating or restarting (the AI Zeny Recovery service brings the Host back by itself), or the Local API was stopped from the AI Zeny window (<strong>Start API</strong> there), or <code>baseUrl</code> has the wrong port.</li>\n<li><code>403 LOCAL_NETWORK_ONLY</code>: you are calling from outside the local network, or through a <code>Host</code> name that is not this PC.</li>\n</ul>\n","urlObject":{"path":["api","v1","health"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"ea58a0a7-6803-fa9b-db76-0e6b1558b80c","name":"200 OK – Host is alive","originalRequest":{"auth":{"type":"noauth"},"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/health","description":"**Local** · `GET {{baseUrl}}/api/v1/health` · no token · Read only — does not write to BUSY\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Run this first.** Liveness of the AI Zeny Host. The only route that needs **no token**.\n\nReturns the Host version and uptime in seconds, nothing else (no tenant, enrollment, path or configuration detail).\n\n- `200` `{ \"success\": true, \"data\": { \"status\": \"ok\", \"version\": \"0.0.7\", \"uptimeSec\": 36971 }, \"metadata\": {} }`\n- No answer at all: AI Zeny may be starting, updating or restarting (the AI Zeny Recovery service brings the Host back by itself), or the Local API was stopped from the AI Zeny window (**Start API** there), or `baseUrl` has the wrong port.\n- `403 LOCAL_NETWORK_ONLY`: you are calling from outside the local network, or through a `Host` name that is not this PC."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"d8ba217074354b58b79d78973db0b38e","key":"X-Request-Id"},{"value":"no-store","key":"Cache-Control"},{"value":"nosniff","key":"X-Content-Type-Options"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"status\":\"ok\",\"version\":\"0.0.7\",\"uptimeSec\":36971},\"metadata\":{}}"}],"_postman_id":"deb68ede-bf6e-73fb-e88c-15292d527061"},{"name":"Status","id":"d3a85db0-e81b-d359-5f93-ce0c82f131ee","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/status","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/status</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Run this second: proves the Bearer token.</strong> The full status of the Host: version and mode, the four components (Health Check, Local API, Pusher, Updater), the GUI presence, enrollment and subscription summary, access decision and unlock-credential state, the automatic updater (D41) and the relay counters.</p>\n<p>Never contains a token, device credential, enrollment code, PIN, verifier or accounting data.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Meaning</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>Token accepted.</td>\n</tr>\n<tr>\n<td>401 <code>UNAUTHORIZED</code></td>\n<td><code>localApiToken</code> is missing or wrong (header <code>WWW-Authenticate: Bearer</code>). Copy the token again from AI Zeny.</td>\n</tr>\n</tbody>\n</table>\n</div><p>Key members: <code>host.version</code>, <code>components[].state</code> (<code>running</code>, <code>starting</code>, <code>stopped</code>, <code>failed</code>) and <code>reason</code>, <code>enrollment.state</code>, <code>access.decision</code>, <code>updates.phase</code> (<code>upToDate</code>, <code>downloading</code>, <code>applying</code>, <code>retrying</code>, <code>blocked</code>, …), <code>relay</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","status"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"12b4d20e-2b7c-8c1b-88d1-46e9ae602533","name":"200 OK – full status","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/status","description":"**Local** · `GET {{baseUrl}}/api/v1/status` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Run this second: proves the Bearer token.** The full status of the Host: version and mode, the four components (Health Check, Local API, Pusher, Updater), the GUI presence, enrollment and subscription summary, access decision and unlock-credential state, the automatic updater (D41) and the relay counters.\n\nNever contains a token, device credential, enrollment code, PIN, verifier or accounting data.\n\n| Status | Meaning |\n|---|---|\n| 200 | Token accepted. |\n| 401 `UNAUTHORIZED` | `localApiToken` is missing or wrong (header `WWW-Authenticate: Bearer`). Copy the token again from AI Zeny. |\n\nKey members: `host.version`, `components[].state` (`running`, `starting`, `stopped`, `failed`) and `reason`, `enrollment.state`, `access.decision`, `updates.phase` (`upToDate`, `downloading`, `applying`, `retrying`, `blocked`, …), `relay`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"4f0c2b8e5a9d4c1f9b7e6a5d4c3b2a10","key":"X-Request-Id"},{"value":"no-store","key":"Cache-Control"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"host\": { \"version\": \"0.0.7\", \"mode\": \"service\", \"startedUtc\": \"2026-09-26T08:48:12.4678712+00:00\", \"uptimeSec\": 36971, \"maintenance\": false },\n    \"components\": [\n      { \"name\": \"AI Zeny Health Check\", \"slug\": \"health-check\", \"state\": \"running\", \"lastHeartbeatUtc\": \"2026-09-26T08:55:16.8009654+00:00\", \"strikes\": 0, \"restartCount\": 0, \"reason\": null, \"manualRestartAllowed\": false },\n      { \"name\": \"AI Zeny Local API\", \"slug\": \"local-api\", \"state\": \"running\", \"lastHeartbeatUtc\": \"2026-09-26T08:55:10.1897394+00:00\", \"strikes\": 0, \"restartCount\": 0, \"reason\": null, \"manualRestartAllowed\": false },\n      { \"name\": \"AI Zeny Pusher\", \"slug\": \"pusher\", \"state\": \"running\", \"lastHeartbeatUtc\": \"2026-09-26T08:55:10.1897235+00:00\", \"strikes\": 0, \"restartCount\": 0, \"reason\": null, \"manualRestartAllowed\": true },\n      { \"name\": \"AI Zeny Updater\", \"slug\": \"updater\", \"state\": \"running\", \"lastHeartbeatUtc\": \"2026-09-26T08:55:12.1281536+00:00\", \"strikes\": 0, \"restartCount\": 0, \"reason\": null, \"manualRestartAllowed\": true }\n    ],\n    \"gui\": { \"expected\": true, \"processId\": 1234, \"sessionId\": 1, \"reportedUtc\": \"2026-09-26T08:48:17.1401437+00:00\" },\n    \"enrollment\": {\n      \"state\": \"enrolled\", \"activity\": \"refreshing\", \"reasonCode\": null,\n      \"organizationId\": \"org_EXAMPLE0000000000000000000\", \"organizationName\": \"Example Organization\",\n      \"subscription\": { \"status\": \"trialing\", \"periodStartUtc\": \"2026-09-25T08:31:31.397+00:00\", \"periodEndUtc\": \"2026-09-28T08:31:31.397+00:00\", \"plan\": \"trial\", \"refreshedUtc\": \"2026-09-26T08:48:13.6870519+00:00\" },\n      \"lastErrorCode\": null, \"lastCloudContactUtc\": \"2026-09-26T08:55:23.5292653+00:00\", \"cloudConfigured\": true\n    },\n    \"access\": {\n      \"decision\": \"loginAllowed\", \"subscriptionEndsUtc\": \"2026-09-28T08:31:31.397+00:00\", \"lastSuccessfulContactUtc\": \"2026-09-26T08:48:13.6870519+00:00\",\n      \"stale\": false, \"idleTimeoutSeconds\": 900,\n      \"unlockCredential\": { \"set\": true, \"kind\": \"pin\", \"updatedUtc\": \"2026-09-25T10:17:38.7055017+00:00\", \"resetAuthorized\": false }\n    },\n    \"updates\": {\n      \"configured\": true, \"serviceRunning\": true, \"phase\": \"upToDate\", \"installedVersion\": \"0.0.7\", \"availableVersion\": null, \"code\": null,\n      \"lastCheckUtc\": \"2026-09-26T08:47:40.8478028+00:00\", \"nextCheckUtc\": \"2026-09-26T11:47:41.644864+00:00\",\n      \"lastAttempt\": { \"fromVersion\": \"0.0.6\", \"toVersion\": \"0.0.7\", \"succeeded\": true, \"code\": null, \"package\": \"delta\", \"completedUtc\": \"2026-09-26T08:48:16.2152596+00:00\" },\n      \"updaterVersion\": \"0.0.7\"\n    },\n    \"relay\": {\n      \"listenerActive\": true, \"pollState\": \"polling\", \"queueDepth\": 0, \"inFlight\": 0,\n      \"lastCommandReceivedUtc\": null, \"lastVerifiedCommandUtc\": null, \"lastResultPostedUtc\": null, \"lastPollUtc\": \"2026-09-26T08:55:23.5292673+00:00\",\n      \"lastFailureCode\": null, \"received\": 0, \"verified\": 0, \"rejected\": 0, \"duplicates\": 0, \"resultsPosted\": 0, \"resultsAbandoned\": 0, \"executorsAvailable\": true\n    }\n  },\n  \"metadata\": {}\n}"},{"id":"f5859f9b-23b1-45f9-364d-17943060e328","name":"401 Unauthorized – missing or wrong token","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/status","description":"**Local** · `GET {{baseUrl}}/api/v1/status` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Run this second: proves the Bearer token.** The full status of the Host: version and mode, the four components (Health Check, Local API, Pusher, Updater), the GUI presence, enrollment and subscription summary, access decision and unlock-credential state, the automatic updater (D41) and the relay counters.\n\nNever contains a token, device credential, enrollment code, PIN, verifier or accounting data.\n\n| Status | Meaning |\n|---|---|\n| 200 | Token accepted. |\n| 401 `UNAUTHORIZED` | `localApiToken` is missing or wrong (header `WWW-Authenticate: Bearer`). Copy the token again from AI Zeny. |\n\nKey members: `host.version`, `components[].state` (`running`, `starting`, `stopped`, `failed`) and `reason`, `enrollment.state`, `access.decision`, `updates.phase` (`upToDate`, `downloading`, `applying`, `retrying`, `blocked`, …), `relay`."},"status":"Unauthorized","code":401,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"WWW-Authenticate","value":"Bearer"},{"key":"X-Request-Id","value":"77b0dd3be08a4f0885d2e4c222eeebfb"},{"key":"Cache-Control","value":"no-store"}],"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"UNAUTHORIZED\",\"message\":\"A valid \\\"Authorization: Bearer <local-api-token>\\\" header is required.\"},\"requestId\":\"77b0dd3be08a4f0885d2e4c222eeebfb\"}}"}],"_postman_id":"d3a85db0-e81b-d359-5f93-ce0c82f131ee"},{"name":"Component health","id":"89cde63a-62fd-bc62-c2e0-f746f4fabfc8","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/health/components","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/health/components</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>The four supervised components with their state, strikes and restart counts, plus the 50 most recent state transitions (for example a Pusher <code>running → failed</code> with reason <code>PUSHER_RETRYING</code>, then <code>RECOVERED</code>). Read only.</p>\n<p><code>manualRestartAllowed</code> says whether <em>Restart a component</em> (Mutating folder) may be used for that component: only <code>pusher</code> and <code>updater</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","health","components"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"99ac06d9-1fed-724a-8431-1fee10dbfc5d","name":"200 OK – components and recent transitions","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/health/components","description":"**Local** · `GET {{baseUrl}}/api/v1/health/components` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\nThe four supervised components with their state, strikes and restart counts, plus the 50 most recent state transitions (for example a Pusher `running → failed` with reason `PUSHER_RETRYING`, then `RECOVERED`). Read only.\n\n`manualRestartAllowed` says whether *Restart a component* (Mutating folder) may be used for that component: only `pusher` and `updater`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"0a1b2c3d4e5f60718293a4b5c6d7e8f9","key":"X-Request-Id"},{"value":"no-store","key":"Cache-Control"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"components\": [\n      { \"name\": \"AI Zeny Health Check\", \"slug\": \"health-check\", \"state\": \"running\", \"lastHeartbeatUtc\": \"2026-09-26T05:35:16.8009654+00:00\", \"strikes\": 0, \"restartCount\": 0, \"reason\": null, \"manualRestartAllowed\": false },\n      { \"name\": \"AI Zeny Local API\", \"slug\": \"local-api\", \"state\": \"running\", \"lastHeartbeatUtc\": \"2026-09-26T05:35:10.1897394+00:00\", \"strikes\": 0, \"restartCount\": 0, \"reason\": null, \"manualRestartAllowed\": false },\n      { \"name\": \"AI Zeny Pusher\", \"slug\": \"pusher\", \"state\": \"running\", \"lastHeartbeatUtc\": \"2026-09-26T05:35:10.1897235+00:00\", \"strikes\": 0, \"restartCount\": 0, \"reason\": null, \"manualRestartAllowed\": true },\n      { \"name\": \"AI Zeny Updater\", \"slug\": \"updater\", \"state\": \"running\", \"lastHeartbeatUtc\": \"2026-09-26T05:35:12.1281536+00:00\", \"strikes\": 0, \"restartCount\": 0, \"reason\": null, \"manualRestartAllowed\": true }\n    ],\n    \"recentTransitions\": [\n      { \"occurredUtc\": \"2026-09-26T04:56:59.6029721+00:00\", \"service\": \"AI Zeny Pusher\", \"from\": \"failed\", \"to\": \"running\", \"code\": \"RECOVERED\", \"reason\": null },\n      { \"occurredUtc\": \"2026-09-26T04:56:14.5272979+00:00\", \"service\": \"AI Zeny Pusher\", \"from\": \"running\", \"to\": \"failed\", \"code\": \"FAULTED\", \"reason\": \"PUSHER_RETRYING\" }\n    ]\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"89cde63a-62fd-bc62-c2e0-f746f4fabfc8"},{"name":"Status without a token (expects 401)","id":"35623676-d867-3d02-6b42-36ac66b64b65","request":{"auth":{"type":"noauth","isInherited":false},"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/status","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/status</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>Negative check of D39: without <code>Authorization: Bearer …</code> every route except <code>/health</code> answers <code>401 UNAUTHORIZED</code> with <code>WWW-Authenticate: Bearer</code>. Safe to run any time.</p>\n","urlObject":{"path":["api","v1","status"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"624d6748-3532-a8e8-8c8b-6bf50407e54a","name":"401 Unauthorized","originalRequest":{"auth":{"type":"noauth"},"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/status","description":"**Local** · `GET {{baseUrl}}/api/v1/status` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\nNegative check of D39: without `Authorization: Bearer …` every route except `/health` answers `401 UNAUTHORIZED` with `WWW-Authenticate: Bearer`. Safe to run any time."},"status":"Unauthorized","code":401,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"Bearer","key":"WWW-Authenticate"},{"value":"77b0dd3be08a4f0885d2e4c222eeebfb","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"UNAUTHORIZED\",\"message\":\"A valid \\\"Authorization: Bearer <local-api-token>\\\" header is required.\"},\"requestId\":\"77b0dd3be08a4f0885d2e4c222eeebfb\"}}"}],"_postman_id":"35623676-d867-3d02-6b42-36ac66b64b65"},{"name":"List BUSY companies","id":"f1a774ed-04f0-498d-5da1-67edceaf21bd","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/companies","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/busy/companies</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata, configuration }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>Every BUSY company configured in AI Zeny on this PC, ordered by company code. Since 0.0.9 the answer keeps <strong>BUSY's data</strong> and <strong>AI Zeny's saved settings</strong> apart:</p>\n<ul>\n<li><strong><code>data</code></strong> — one flat item per company with only what BUSY itself says, read live from BUSY's <code>Company</code> table (read only, one company at a time, 30 s per company): <code>companyCode</code>, <code>name</code>, <code>printName</code>, <code>shortName</code>, <code>addressLines</code> (<code>Address1</code>..<code>Address4</code>, empty lines left out), <code>city</code>, <code>pinCode</code>, <code>phone</code>, <code>email</code>, <code>gstNumber</code>, <code>panNumber</code>, <code>tanNumber</code>, <code>cinNumber</code>, <code>drugLicenseNumbers</code>, <code>booksStartDate</code> (<code>yyyy-MM-dd</code>), <code>financialYears</code> (the four-digit starting years BUSY has). Use these for report and invoice headers.</li>\n<li><strong><code>metadata</code></strong> — <code>companyLimit</code>, <code>financialYearLimit</code> (<code>null</code> = not known yet), <code>busyDetails</code>, <code>elapsedMs</code> and <strong><code>busyRead</code></strong>: per company <code>{ companyCode, status: \"ok\" | \"unavailable\", code, message, readUtc }</code>. A company BUSY cannot answer for is reported here (<code>BUSY_UNAVAILABLE</code>, <code>BUSY_COMPANY_NOT_FOUND</code>, <code>BUSY_TIMEOUT</code>, …); the list stays a success.</li>\n<li><strong><code>configuration</code></strong> (always the last member) — AI Zeny's saved settings per company: <code>companyCode</code>, <code>displayName</code> (the friendly name saved in AI Zeny), <code>provider</code> (<code>sqlServer</code> or <code>access</code>) with exactly one of <code>sqlServer</code> / <code>access</code>, <code>enabled</code>, <code>allowedFinancialYears</code> (four-digit starting years, <code>\"2026\"</code> = April 2026 – March 2027), <code>lastTest { code, testedUtc }</code>, <code>updatedUtc</code>. Passwords are never returned: <code>sqlServer.hasPassword</code> only says whether one is stored.</li>\n</ul>\n<p>Never returned: BUSY online-service passwords and user names, keys and serials, personal details of the TDS / VAT person, accountant and CA.</p>\n<p>Query <code>busy=false</code> skips BUSY: <code>data</code> is <code>[]</code>, <code>metadata.busyRead</code> is <code>[]</code>, <code>configuration</code> is still complete. Any other value than <code>true</code>/<code>false</code> is <code>400 BAD_REQUEST</code> with <code>field: \"busy\"</code>.</p>\n<p>Each company has <strong>one</strong> <code>companyCode</code> (BUSY's company code, <code>^[A-Z0-9_-]{1,32}$</code>, D38). Use a <code>companyCode</code> from here as the environment's <code>companyCode</code> for the V1 data operations.</p>\n<p><em>Known collection issue (2026-10-18 acceptance audit): the collection-level check \"Envelope: exactly success, data, metadata in that order\" predates the optional last <code>configuration</code> member and fails on this request only; it should accept <code>configuration</code> as a fourth, last member on a success.</em></p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","companies"],"host":["{{baseUrl}}"],"query":[{"disabled":true,"description":{"content":"<p>true (default): read each company's own details live from BUSY into <code>busy</code>. false: only the saved configuration.</p>\n","type":"text/plain"},"key":"busy","value":"true"}],"variable":[]}},"response":[{"id":"d3c40629-2dfa-d839-914c-e23dee8c2d09","name":"200 OK – one company read from BUSY, one BUSY could not answer for","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{baseUrl}}/api/v1/busy/companies","host":["{{baseUrl}}"],"path":["api","v1","busy","companies"],"query":[{"value":"true","description":"true (default): read each company's own details live from BUSY into `busy`. false: only the saved configuration.","key":"busy","disabled":true}]},"description":"**Local** · `GET {{baseUrl}}/api/v1/busy/companies` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Answer:** `{ success, data, metadata, configuration }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\nEvery BUSY company configured in AI Zeny on this PC, ordered by company code. Since 0.0.9 the answer keeps **BUSY's data** and **AI Zeny's saved settings** apart:\n\n- **`data`** — one flat item per company with only what BUSY itself says, read live from BUSY's `Company` table (read only, one company at a time, 30 s per company): `companyCode`, `name`, `printName`, `shortName`, `addressLines` (`Address1`..`Address4`, empty lines left out), `city`, `pinCode`, `phone`, `email`, `gstNumber`, `panNumber`, `tanNumber`, `cinNumber`, `drugLicenseNumbers`, `booksStartDate` (`yyyy-MM-dd`), `financialYears` (the four-digit starting years BUSY has). Use these for report and invoice headers.\n- **`metadata`** — `companyLimit`, `financialYearLimit` (`null` = not known yet), `busyDetails`, `elapsedMs` and **`busyRead`**: per company `{ companyCode, status: \"ok\" | \"unavailable\", code, message, readUtc }`. A company BUSY cannot answer for is reported here (`BUSY_UNAVAILABLE`, `BUSY_COMPANY_NOT_FOUND`, `BUSY_TIMEOUT`, …); the list stays a success.\n- **`configuration`** (always the last member) — AI Zeny's saved settings per company: `companyCode`, `displayName` (the friendly name saved in AI Zeny), `provider` (`sqlServer` or `access`) with exactly one of `sqlServer` / `access`, `enabled`, `allowedFinancialYears` (four-digit starting years, `\"2026\"` = April 2026 – March 2027), `lastTest { code, testedUtc }`, `updatedUtc`. Passwords are never returned: `sqlServer.hasPassword` only says whether one is stored.\n\nNever returned: BUSY online-service passwords and user names, keys and serials, personal details of the TDS / VAT person, accountant and CA.\n\nQuery `busy=false` skips BUSY: `data` is `[]`, `metadata.busyRead` is `[]`, `configuration` is still complete. Any other value than `true`/`false` is `400 BAD_REQUEST` with `field: \"busy\"`.\n\nEach company has **one** `companyCode` (BUSY's company code, `^[A-Z0-9_-]{1,32}$`, D38). Use a `companyCode` from here as the environment's `companyCode` for the V1 data operations.\n\n_Known collection issue (2026-10-18 acceptance audit): the collection-level check \"Envelope: exactly success, data, metadata in that order\" predates the optional last `configuration` member and fails on this request only; it should accept `configuration` as a fourth, last member on a success._"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"5e6f7a8b9c0d41e2a3b4c5d6e7f80912"},{"key":"Cache-Control","value":"no-store"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    {\n      \"companyCode\": \"COMP0001\",\n      \"displayName\": \"Traders (main)\",\n      \"provider\": \"sqlServer\",\n      \"sqlServer\": { \"server\": \"BUSYSERVER\\\\SQLEXPRESS\", \"port\": null, \"authentication\": \"sqlLogin\", \"userName\": \"busyreader\", \"hasPassword\": true, \"encrypt\": true, \"trustServerCertificate\": true },\n      \"access\": null,\n      \"enabled\": true,\n      \"lastValidatedUtc\": \"2026-09-25T10:40:12.1234567+00:00\",\n      \"lastValidationCode\": \"OK\",\n      \"allowedFinancialYears\": [\"2026\"],\n      \"foundFinancialYears\": [\"2025\", \"2026\"],\n      \"updatedUtc\": \"2026-09-25T10:40:12.1234567+00:00\",\n      \"busy\": {\n        \"status\": \"ok\",\n        \"code\": null,\n        \"message\": null,\n        \"profile\": {\n          \"name\": \"Example Traders Pvt Ltd\",\n          \"printName\": \"EXAMPLE TRADERS PVT LTD\",\n          \"shortName\": \"ETPL\",\n          \"addressLines\": [\"12 Example Road\", \"Industrial Area\"],\n          \"city\": \"Jaipur\",\n          \"pinCode\": \"302001\",\n          \"phone\": \"0141-0000000\",\n          \"email\": \"accounts@example.com\",\n          \"gstNumber\": \"08ABCDE1234F1Z5\",\n          \"panNumber\": \"ABCDE1234F\",\n          \"tanNumber\": null,\n          \"cinNumber\": null,\n          \"drugLicenseNumbers\": [],\n          \"booksStartDate\": \"2025-04-01\"\n        },\n        \"financialYears\": [\"2025\", \"2026\"],\n        \"readUtc\": \"2026-09-26T09:31:05.1234567+00:00\"\n      }\n    },\n    {\n      \"companyCode\": \"COMP0002\",\n      \"displayName\": \"Stores\",\n      \"provider\": \"access\",\n      \"sqlServer\": null,\n      \"access\": { \"dataFolder\": \"C:\\\\BusyWin\\\\DATA\" },\n      \"enabled\": false,\n      \"lastValidatedUtc\": null,\n      \"lastValidationCode\": null,\n      \"allowedFinancialYears\": [\"2025\", \"2026\"],\n      \"foundFinancialYears\": [],\n      \"updatedUtc\": \"2026-09-25T11:02:45.7654321+00:00\",\n      \"busy\": {\n        \"status\": \"unavailable\",\n        \"code\": \"BUSY_COMPANY_NOT_FOUND\",\n        \"message\": \"The BUSY company was not found with this PC's settings.\",\n        \"profile\": null,\n        \"financialYears\": [],\n        \"readUtc\": \"2026-09-26T09:31:05.2345678+00:00\"\n      }\n    }\n  ],\n  \"metadata\": { \"companyLimit\": 3, \"financialYearLimit\": 2, \"busyDetails\": true, \"elapsedMs\": 567 }\n}"}],"_postman_id":"f1a774ed-04f0-498d-5da1-67edceaf21bd"}],"id":"b9adc6d1-1fee-4c15-b952-8f8c0b921962","description":"<p>Liveness, full status, component health and the configured BUSY companies. Read only; <code>/api/v1/health</code> needs no token, everything else the Bearer token.</p>\n","_postman_id":"b9adc6d1-1fee-4c15-b952-8f8c0b921962","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Master Reads (read only)","item":[{"name":"busy.units.query – Units of measure","id":"9b0250ea-aef4-83d8-c312-5661dea3e41a","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"search\": \"\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/units/query","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/units/query</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.units.query</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>V1 operation <code>busy.units.query</code></strong> — the units of measure (BUSY <code>Master1</code>, <code>MasterType = 8</code>) of one configured company in one financial year. <strong>Read only</strong> (POST only because it has a JSON body). SQL Server reads run in an always rolled-back transaction; Access files are opened read-only.</p>\n<h3 id=\"request-unknown-members-are-refused\">Request (unknown members are refused)</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Member</th>\n<th>Type</th>\n<th>Rule</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>companyCode</code></td>\n<td>string, required</td>\n<td>The company's one company code as set up in AI Zeny, <code>^[A-Z0-9_-]{1,32}$</code>.</td>\n</tr>\n<tr>\n<td><code>financialYear</code></td>\n<td>string, required</td>\n<td>Exactly four digits: the starting year (<code>2026</code> = April 2026 – March 2027). No <code>2026-27</code>. Must be one of the company's allowed years.</td>\n</tr>\n<tr>\n<td><code>search</code></td>\n<td>string, optional</td>\n<td>Up to 100 characters. Matches the unit id exactly, or part of the name, alias or print name (case-insensitive). Empty = all.</td>\n</tr>\n<tr>\n<td><code>page</code></td>\n<td>number, optional</td>\n<td>1 – 10 000, default 1.</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>number, optional</td>\n<td>1 – 200, default 100.</td>\n</tr>\n</tbody>\n</table>\n</div><p>At most 1 000 units are read from one year (more is <code>RESULT_TOO_LARGE</code>); one call is bounded to 45 s.</p>\n<h3 id=\"response-200\">Response (200)</h3>\n<p><code>data</code> is the <strong>array of units</strong> (<code>unitId</code>, <code>name</code>, <code>alias</code>, <code>printName</code>), ordered by name, then id. No match is still <code>success: true</code> with <code>\"data\": []</code>. <code>metadata</code> is <code>{ apiVersion: \"v1\", operation: \"busy.units.query\", requestId, elapsedMs, filters: { companyCode, financialYear, search }, pagination: { page, pageSize, returned, totalRows, hasMore, nextPage } }</code>.</p>\n<h3 id=\"errors-success-false-data-null-metadataerror--code-message-field--metadataapiversion-v1\">Errors (<code>success: false</code>, <code>data: null</code>, <code>metadata.error { code, message[, field] }</code>, <code>metadata.apiVersion: \"v1\"</code>)</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>400</td>\n<td><code>BAD_REQUEST</code> (not the documented JSON), <code>INVALID_PARAMETER</code> (a member out of rule; <code>field</code> names it)</td>\n</tr>\n<tr>\n<td>403</td>\n<td><code>FINANCIAL_YEAR_NOT_ALLOWED</code></td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>COMPANY_NOT_CONFIGURED</code>, <code>BUSY_COMPANY_NOT_FOUND</code>, <code>BUSY_FINANCIAL_YEAR_NOT_AVAILABLE</code></td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>COMPANY_DISABLED</code>, <code>COMPANY_CONNECTION_NOT_CONFIGURED</code>, <code>BUSY_COMPANY_LOCKED</code></td>\n</tr>\n<tr>\n<td>422</td>\n<td><code>BUSY_SCHEMA_UNSUPPORTED</code>, <code>RESULT_TOO_LARGE</code></td>\n</tr>\n<tr>\n<td>503</td>\n<td><code>BUSY_UNAVAILABLE</code>, <code>BUSY_CONFIGURATION_UNAVAILABLE</code></td>\n</tr>\n<tr>\n<td>504</td>\n<td><code>BUSY_TIMEOUT</code></td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","units","query"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"beb939bb-bb3f-1763-fe58-90b8b7f85082","name":"200 OK – units","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"search\": \"\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/units/query","description":"**Local** · `POST {{baseUrl}}/api/v1/busy/units/query` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.units.query`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**V1 operation `busy.units.query`** — the units of measure (BUSY `Master1`, `MasterType = 8`) of one configured company in one financial year. **Read only** (POST only because it has a JSON body). SQL Server reads run in an always rolled-back transaction; Access files are opened read-only.\n\n### Request (unknown members are refused)\n\n| Member | Type | Rule |\n|---|---|---|\n| `companyCode` | string, required | The company's one company code as set up in AI Zeny, `^[A-Z0-9_-]{1,32}$`. |\n| `financialYear` | string, required | Exactly four digits: the starting year (`2026` = April 2026 – March 2027). No `2026-27`. Must be one of the company's allowed years. |\n| `search` | string, optional | Up to 100 characters. Matches the unit id exactly, or part of the name, alias or print name (case-insensitive). Empty = all. |\n| `page` | number, optional | 1 – 10 000, default 1. |\n| `pageSize` | number, optional | 1 – 200, default 100. |\n\nAt most 1 000 units are read from one year (more is `RESULT_TOO_LARGE`); one call is bounded to 45 s.\n\n### Response (200)\n\n`data` is the **array of units** (`unitId`, `name`, `alias`, `printName`), ordered by name, then id. No match is still `success: true` with `\"data\": []`. `metadata` is `{ apiVersion: \"v1\", operation: \"busy.units.query\", requestId, elapsedMs, filters: { companyCode, financialYear, search }, pagination: { page, pageSize, returned, totalRows, hasMore, nextPage } }`.\n\n### Errors (`success: false`, `data: null`, `metadata.error { code, message[, field] }`, `metadata.apiVersion: \"v1\"`)\n\n| Status | Code |\n|---|---|\n| 400 | `BAD_REQUEST` (not the documented JSON), `INVALID_PARAMETER` (a member out of rule; `field` names it) |\n| 403 | `FINANCIAL_YEAR_NOT_ALLOWED` |\n| 404 | `COMPANY_NOT_CONFIGURED`, `BUSY_COMPANY_NOT_FOUND`, `BUSY_FINANCIAL_YEAR_NOT_AVAILABLE` |\n| 409 | `COMPANY_DISABLED`, `COMPANY_CONNECTION_NOT_CONFIGURED`, `BUSY_COMPANY_LOCKED` |\n| 422 | `BUSY_SCHEMA_UNSUPPORTED`, `RESULT_TOO_LARGE` |\n| 503 | `BUSY_UNAVAILABLE`, `BUSY_CONFIGURATION_UNAVAILABLE` |\n| 504 | `BUSY_TIMEOUT` |"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"9a8b7c6d5e4f40312a1b0c9d8e7f6a5b","key":"X-Request-Id"},{"value":"no-store","key":"Cache-Control"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    { \"unitId\": \"101\", \"name\": \"Kgs\", \"alias\": \"Kilogram\", \"printName\": \"Kgs\" },\n    { \"unitId\": \"100\", \"name\": \"Pcs\", \"alias\": null, \"printName\": \"Pcs\" }\n  ],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.units.query\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\n    \"elapsedMs\": 38,\n    \"filters\": { \"companyCode\": \"COMP0001\", \"financialYear\": \"2026\", \"search\": null },\n    \"pagination\": { \"page\": 1, \"pageSize\": 5, \"returned\": 2, \"totalRows\": 2, \"hasMore\": false, \"nextPage\": null }\n  }\n}"},{"id":"7341d9c3-2985-0ef2-6f21-a48842dea400","name":"400 INVALID_PARAMETER – year not four digits","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"search\": \"\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/units/query","description":"**Local** · `POST {{baseUrl}}/api/v1/busy/units/query` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.units.query`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**V1 operation `busy.units.query`** — the units of measure (BUSY `Master1`, `MasterType = 8`) of one configured company in one financial year. **Read only** (POST only because it has a JSON body). SQL Server reads run in an always rolled-back transaction; Access files are opened read-only.\n\n### Request (unknown members are refused)\n\n| Member | Type | Rule |\n|---|---|---|\n| `companyCode` | string, required | The company's one company code as set up in AI Zeny, `^[A-Z0-9_-]{1,32}$`. |\n| `financialYear` | string, required | Exactly four digits: the starting year (`2026` = April 2026 – March 2027). No `2026-27`. Must be one of the company's allowed years. |\n| `search` | string, optional | Up to 100 characters. Matches the unit id exactly, or part of the name, alias or print name (case-insensitive). Empty = all. |\n| `page` | number, optional | 1 – 10 000, default 1. |\n| `pageSize` | number, optional | 1 – 200, default 100. |\n\nAt most 1 000 units are read from one year (more is `RESULT_TOO_LARGE`); one call is bounded to 45 s.\n\n### Response (200)\n\n`data` is the **array of units** (`unitId`, `name`, `alias`, `printName`), ordered by name, then id. No match is still `success: true` with `\"data\": []`. `metadata` is `{ apiVersion: \"v1\", operation: \"busy.units.query\", requestId, elapsedMs, filters: { companyCode, financialYear, search }, pagination: { page, pageSize, returned, totalRows, hasMore, nextPage } }`.\n\n### Errors (`success: false`, `data: null`, `metadata.error { code, message[, field] }`, `metadata.apiVersion: \"v1\"`)\n\n| Status | Code |\n|---|---|\n| 400 | `BAD_REQUEST` (not the documented JSON), `INVALID_PARAMETER` (a member out of rule; `field` names it) |\n| 403 | `FINANCIAL_YEAR_NOT_ALLOWED` |\n| 404 | `COMPANY_NOT_CONFIGURED`, `BUSY_COMPANY_NOT_FOUND`, `BUSY_FINANCIAL_YEAR_NOT_AVAILABLE` |\n| 409 | `COMPANY_DISABLED`, `COMPANY_CONNECTION_NOT_CONFIGURED`, `BUSY_COMPANY_LOCKED` |\n| 422 | `BUSY_SCHEMA_UNSUPPORTED`, `RESULT_TOO_LARGE` |\n| 503 | `BUSY_UNAVAILABLE`, `BUSY_CONFIGURATION_UNAVAILABLE` |\n| 504 | `BUSY_TIMEOUT` |"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"1520164c6a2440059286f972e18efc77","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"INVALID_PARAMETER\",\"message\":\"financialYear is required: the four-digit starting year of the financial year, for example 2026.\",\"field\":\"financialYear\"},\"requestId\":\"1520164c6a2440059286f972e18efc77\",\"apiVersion\":\"v1\"}}"},{"id":"fffa1902-0bd9-0db2-3d0f-aa1cd9a9a20b","name":"404 COMPANY_NOT_CONFIGURED","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"search\": \"\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/units/query","description":"**Local** · `POST {{baseUrl}}/api/v1/busy/units/query` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.units.query`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**V1 operation `busy.units.query`** — the units of measure (BUSY `Master1`, `MasterType = 8`) of one configured company in one financial year. **Read only** (POST only because it has a JSON body). SQL Server reads run in an always rolled-back transaction; Access files are opened read-only.\n\n### Request (unknown members are refused)\n\n| Member | Type | Rule |\n|---|---|---|\n| `companyCode` | string, required | The company's one company code as set up in AI Zeny, `^[A-Z0-9_-]{1,32}$`. |\n| `financialYear` | string, required | Exactly four digits: the starting year (`2026` = April 2026 – March 2027). No `2026-27`. Must be one of the company's allowed years. |\n| `search` | string, optional | Up to 100 characters. Matches the unit id exactly, or part of the name, alias or print name (case-insensitive). Empty = all. |\n| `page` | number, optional | 1 – 10 000, default 1. |\n| `pageSize` | number, optional | 1 – 200, default 100. |\n\nAt most 1 000 units are read from one year (more is `RESULT_TOO_LARGE`); one call is bounded to 45 s.\n\n### Response (200)\n\n`data` is the **array of units** (`unitId`, `name`, `alias`, `printName`), ordered by name, then id. No match is still `success: true` with `\"data\": []`. `metadata` is `{ apiVersion: \"v1\", operation: \"busy.units.query\", requestId, elapsedMs, filters: { companyCode, financialYear, search }, pagination: { page, pageSize, returned, totalRows, hasMore, nextPage } }`.\n\n### Errors (`success: false`, `data: null`, `metadata.error { code, message[, field] }`, `metadata.apiVersion: \"v1\"`)\n\n| Status | Code |\n|---|---|\n| 400 | `BAD_REQUEST` (not the documented JSON), `INVALID_PARAMETER` (a member out of rule; `field` names it) |\n| 403 | `FINANCIAL_YEAR_NOT_ALLOWED` |\n| 404 | `COMPANY_NOT_CONFIGURED`, `BUSY_COMPANY_NOT_FOUND`, `BUSY_FINANCIAL_YEAR_NOT_AVAILABLE` |\n| 409 | `COMPANY_DISABLED`, `COMPANY_CONNECTION_NOT_CONFIGURED`, `BUSY_COMPANY_LOCKED` |\n| 422 | `BUSY_SCHEMA_UNSUPPORTED`, `RESULT_TOO_LARGE` |\n| 503 | `BUSY_UNAVAILABLE`, `BUSY_CONFIGURATION_UNAVAILABLE` |\n| 504 | `BUSY_TIMEOUT` |"},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"fea6dc954fc941bc886264e7764bc4cf"}],"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"COMPANY_NOT_CONFIGURED\",\"message\":\"No company with that company code is set up in AI Zeny on this PC.\"},\"requestId\":\"fea6dc954fc941bc886264e7764bc4cf\",\"apiVersion\":\"v1\"}}"}],"_postman_id":"9b0250ea-aef4-83d8-c312-5661dea3e41a"},{"name":"busy.branches.list – Branches","id":"96b1169e-ca02-22af-77e5-7a94cfcf5328","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/branches","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/branches</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.branches.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.branches.list</code></strong> (BusyNotify <code>POST /v1/branches</code>). Every branch (BUSY <code>Master1</code>, <code>MasterType = 24</code>) of one configured company in one financial year, read <strong>live</strong> from SQL Server or Access (separate statements per provider). <strong>Read only.</strong></p>\n<h3 id=\"request-unknown-members-including-the-references-authtoken--company_id-are-refused\">Request (unknown members, including the reference's <code>authToken</code> / <code>company_id</code>, are refused)</h3>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Member</th>\n<th>Type</th>\n<th>Rule</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>companyCode</code></td>\n<td>string, required</td>\n<td>The company's one company code as set up in AI Zeny (compared upper case).</td>\n</tr>\n<tr>\n<td><code>financialYear</code></td>\n<td>string, required</td>\n<td>Four digits, the starting year (<code>2026</code> = April 2026 – March 2027). Never <code>2026-27</code>. Must be allowed for the company.</td>\n</tr>\n</tbody>\n</table>\n</div><p>Authorization: the collection's <code>Authorization: Bearer {{localApiToken}}</code> only (no <code>X-Session-Id</code>, no <code>X-Api-Key</code>, no body token).</p>\n<h3 id=\"response-200\">Response (200)</h3>\n<p><code>data</code> = array of <code>{ branch_id (number), branch_name (string | null) }</code> (the reference's aliases), <strong>exactly as BUSY stores them</strong> (nothing trimmed), ordered by name (binary) then id; an empty company is <code>data: []</code>. <code>metadata</code> = <code>{ apiVersion, operation, requestId, companyCode, financialYear, rowCount, elapsedMs, executedAt }</code>. <strong>No paging and no row cap</strong> (as the reference); an impossible overflow is an explicit <code>RESULT_TOO_LARGE</code>, never a shortened list.</p>\n<h3 id=\"errors\">Errors</h3>\n<p>400 <code>BAD_REQUEST</code> / <code>INVALID_PARAMETER</code>; 401 <code>UNAUTHORIZED</code>; 403 <code>FINANCIAL_YEAR_NOT_ALLOWED</code>; 404 <code>COMPANY_NOT_CONFIGURED</code>, <code>BUSY_COMPANY_NOT_FOUND</code>, <code>BUSY_FINANCIAL_YEAR_NOT_AVAILABLE</code>; 409 <code>COMPANY_DISABLED</code>, <code>COMPANY_CONNECTION_NOT_CONFIGURED</code>, <code>BUSY_COMPANY_LOCKED</code>; 422 <code>BUSY_SCHEMA_UNSUPPORTED</code>, <code>RESULT_TOO_LARGE</code>; 503 <code>BUSY_UNAVAILABLE</code>; 504 <code>BUSY_TIMEOUT</code>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5a.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","branches"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"96b1169e-ca02-22af-77e5-7a94cfcf5328"},{"name":"busy.categories.list – Categories","id":"1532e2e9-7d38-4914-9e59-3ee187f2e77f","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/categories","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/categories</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.categories.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.categories.list</code></strong> (BusyNotify <code>POST /v1/categories</code>). Every category (BUSY <code>Master1</code>, <code>MasterType = 69</code>) of one configured company in one financial year, read <strong>live</strong> from SQL Server or Access. <strong>Read only.</strong></p>\n<p>Request: <code>{ companyCode, financialYear }</code> only (four-digit year, allowed for the company; unknown members refused). Authorization: the collection's Bearer token only.</p>\n<p>Response (200): <code>data</code> = array of <code>{ category_id (number), category_name }</code>, ordered by name (binary) then id. <code>metadata</code> = <code>{ apiVersion, operation, requestId, companyCode, financialYear, rowCount, elapsedMs, executedAt }</code>.</p>\n<p>Errors and rules: as <strong>busy.branches.list – Branches</strong>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5a.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","categories"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"1532e2e9-7d38-4914-9e59-3ee187f2e77f"},{"name":"busy.product-groups.list – Product groups","id":"253a67c5-1db0-5813-6bfe-5ff89e333e68","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-groups","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/product-groups</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.product-groups.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.product-groups.list</code></strong> (BusyNotify <code>POST /v1/product-groups</code>; reference <code>externalProductsController.getProductGroups</code>). Every product (item) group (BUSY <code>Master1</code>, <code>MasterType = 5</code>) of one configured company in one financial year, read <strong>live</strong> from SQL Server or Access. <strong>Read only.</strong></p>\n<p>Request: <code>{ companyCode, financialYear }</code> only (four-digit year, allowed for the company; unknown members refused). Authorization: the collection's Bearer token only.</p>\n<p>Response (200): <code>data</code> = array of <code>{ product_group_id (number), product_group_name }</code>, ordered by name (binary) then id. <code>metadata</code> = <code>{ apiVersion, operation, requestId, companyCode, financialYear, rowCount, elapsedMs, executedAt }</code>.</p>\n<p>Errors and rules: as <strong>busy.branches.list – Branches</strong>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5a.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","product-groups"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"253a67c5-1db0-5813-6bfe-5ff89e333e68"},{"name":"busy.material-centers.list – Material centres","id":"6b3cf252-b142-5677-83d1-142e39637ec7","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-centers","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/material-centers</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.material-centers.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.material-centers.list</code></strong> (BusyNotify <code>POST /v1/material-centers</code>). Every material centre (BUSY <code>Master1</code>, <code>MasterType = 11</code>) of one configured company in one financial year, read <strong>live</strong> from SQL Server or Access. <strong>Read only.</strong></p>\n<p>Request: <code>{ companyCode, financialYear }</code> only (four-digit year, allowed for the company; unknown members refused). Authorization: the collection's Bearer token only.</p>\n<p>Response (200): <code>data</code> = array of <code>{ mc_id (number), mc_name, mc_alias, mc_print_name }</code>, ordered by name (binary) then id. <code>metadata</code> = <code>{ apiVersion, operation, requestId, companyCode, financialYear, rowCount, elapsedMs, executedAt }</code>.</p>\n<p>Errors and rules: as <strong>busy.branches.list – Branches</strong>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5a.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","material-centers"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"6b3cf252-b142-5677-83d1-142e39637ec7"},{"name":"busy.sale-types.list – Sale types","id":"a1bd0ba9-3ee2-0eb1-0f5c-1fe10eace858","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sale-types","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/sale-types</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.sale-types.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.sale-types.list</code></strong> (BusyNotify <code>POST /v1/sale-types</code>). Every sale type (BUSY <code>Master1</code>, <code>MasterType = 13</code>) of one configured company in one financial year, read <strong>live</strong> from SQL Server or Access. <strong>Read only.</strong></p>\n<p>Request: <code>{ companyCode, financialYear }</code> only (four-digit year, allowed for the company; unknown members refused). Authorization: the collection's Bearer token only.</p>\n<p>Response (200): <code>data</code> = array of <code>{ sale_type_id (number), sale_type_name, sale_type_alias, sale_type_print_name }</code>, ordered by name (binary) then id. <code>metadata</code> = <code>{ apiVersion, operation, requestId, companyCode, financialYear, rowCount, elapsedMs, executedAt }</code>.</p>\n<p>Errors and rules: as <strong>busy.branches.list – Branches</strong>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5a.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","sale-types"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"a1bd0ba9-3ee2-0eb1-0f5c-1fe10eace858"},{"name":"busy.salesmen.list – Salesmen","id":"2407a9aa-0170-6123-b75c-b8dc9a7546c0","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/salesmen","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/salesmen</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.salesmen.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.salesmen.list</code></strong> (BusyNotify <code>POST /v1/salesmen</code>). Every salesman (BUSY <code>Master1</code>, <code>MasterType = 19</code>, left join <code>MasterAddressInfo</code> on the master code) of one configured company in one financial year, read <strong>live</strong> from SQL Server or Access. <strong>Read only.</strong></p>\n<p>Request: <code>{ companyCode, financialYear }</code> only (four-digit year, allowed for the company; unknown members refused). Authorization: the collection's Bearer token only.</p>\n<p>Response (200): <code>data</code> = array of <code>{ salesman_id (number), salesman_name, salesman_alias, mobile_number, whatsapp_number, email }</code>; alias and contact members are <code>\"\"</code> when BUSY holds none (the reference's <code>COALESCE</code>), never null. Ordered by name (binary) then id. <strong>Contains personal contact data.</strong> No paging, no row cap. <code>metadata</code> as the other master lists.</p>\n<p>Errors and rules: as <strong>busy.branches.list – Branches</strong>; a BUSY year without <code>MasterAddressInfo</code> is <code>422 BUSY_SCHEMA_UNSUPPORTED</code>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5b.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","salesmen"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"2407a9aa-0170-6123-b75c-b8dc9a7546c0"},{"name":"busy.voucher-series.list – Voucher series","id":"fa4e4f92-b9c6-790a-6385-9a10c3607c4b","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-series","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/voucher-series</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.voucher-series.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.voucher-series.list</code></strong> (BusyNotify <code>POST /v1/voucher-series</code>). Every voucher series (BUSY <code>Master1</code>, <code>MasterType = 21</code>, <code>I1 = 12</code>) of one configured company in one financial year, read <strong>live</strong> from SQL Server or Access. <strong>Read only.</strong></p>\n<p>Request: <code>{ companyCode, financialYear }</code> only. Authorization: the collection's Bearer token only.</p>\n<p>Response (200): <code>data</code> = array of <code>{ voucher_series_id (number), voucher_series_name }</code>; the name is <code>\"\"</code> when BUSY holds none (the reference's <code>IFNULL(Name, '')</code>). Ordered by name (binary) then id. No paging, no row cap.</p>\n<p>Errors and rules: as <strong>busy.branches.list – Branches</strong>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5b.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","voucher-series"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"fa4e4f92-b9c6-790a-6385-9a10c3607c4b"},{"name":"busy.parameters.list – Item parameters","id":"233cb9e8-678b-336a-0953-493b785914db","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/parameters","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/parameters</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.parameters.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.parameters.list</code></strong> (BusyNotify <code>POST /v1/parameters</code>). The distinct item parameter names (BUSY <code>ItemParamDet.C1</code>) of one configured company in one financial year, read <strong>live</strong> from SQL Server or Access. <strong>Read only.</strong></p>\n<p>Request: <code>{ companyCode, financialYear }</code> only. Authorization: the collection's Bearer token only.</p>\n<p>Response (200): <code>data</code> = array of <code>{ id (number), name }</code>: <code>name</code> is <code>C1</code> with spaces trimmed from both ends (the reference's <code>TRIM</code>), blank names left out, one row per distinct name compared in binary (case matters), in binary order. <strong><code>id</code> is the name's position 1..n in that order</strong> (owner decision: BUSY's <code>ItemParamDet</code> has no id column; the reference's <code>MIN(id)</code> came from its SQLite copy). No paging, no row cap.</p>\n<p>Errors and rules: as <strong>busy.branches.list – Branches</strong>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5b.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","parameters"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"233cb9e8-678b-336a-0953-493b785914db"},{"name":"busy.products.list – Products","id":"39032243-2b18-80a0-5d40-b266d6e551af","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"inStockOnly\": false,\n  \"includePendingSalesOrder\": false,\n  \"parametersStock\": false,\n  \"optionalFields\": false,\n  \"erpCategories\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/products","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/products</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.products.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.products.list</code></strong> (BusyNotify <code>POST /v1/products</code>). Every product (BUSY <code>Master1</code>, <code>MasterType = 6</code>) with stock, prices, units, tax and the 15 multiple aliases, read <strong>live</strong> from SQL Server or Access. <strong>Read only.</strong></p>\n<h3 id=\"request-unknown-members-refused-booleans-json-booleans-numbers-json-numbers\">Request (unknown members refused; booleans JSON booleans, numbers JSON numbers)</h3>\n<p><code>companyCode</code>, <code>financialYear</code> (four digits) required. Optional: <code>materialCenterIds</code> (non-empty unique positive numbers), <code>includePendingSalesOrder</code>, <code>inStockOnly</code>, <code>parametersStock</code>, <code>optionalFields</code>, <code>erpCategories</code> (booleans, default false), <code>priceCategory</code> (1–26). Authorization: the collection's Bearer token only.</p>\n<h3 id=\"response-200\">Response (200)</h3>\n<p><code>data</code> = products in name order (binary), then code: <code>product_id</code>, <code>product_name</code>, <code>product_alias</code>, <code>product_print_name</code>, prices, group, units, material centre, tax, <code>product_stock</code>, descriptions, <code>product_alias_1</code>…<code>15</code>, created/modified. With the switches: <code>parameters</code> {name: stock}, <code>optional_fields</code> {name: {field_key, value}}, <code>erp_categories</code> [{category_id, category_name}]. <code>metadata</code> = <code>{ apiVersion, operation, requestId, companyCode, financialYear, rowCount, elapsedMs, executedAt, filters }</code>. No paging, no row cap.</p>\n<p>Errors as <strong>busy.branches.list – Branches</strong> plus <code>INVALID_PARAMETER</code> for <code>materialCenterIds</code> / <code>priceCategory</code>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5c.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","products"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"39032243-2b18-80a0-5d40-b266d6e551af"},{"name":"busy.products.page – Products pagination","id":"a78b7a38-ec4b-04d1-dccd-1dbfaa859a86","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 50\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/products-pagination","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/products-pagination</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>page</code>, <code>pageSize</code> · operation <code>busy.products.page</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.products.page</code></strong> (BusyNotify <code>POST /v1/products-pagination</code>). One page of the products list. <strong>Read only.</strong></p>\n<p>Request: the <code>/products</code> members plus <code>page</code> and <code>pageSize</code> (required, whole numbers from 1; no page-size maximum).</p>\n<p>Response (200): <code>data</code> = the page's products (same rows as <code>/products</code>). Pages count <strong>distinct products</strong> in name order (binary), then code; detail rows never duplicate a product. <code>metadata</code> adds <code>page</code>, <code>pageSize</code>, <code>totalCount</code>, <code>totalPages</code>, <code>hasNextPage</code>, <code>hasPreviousPage</code>; a page past the end is <code>success: true</code> with <code>data: []</code> and the truthful counts.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5c.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","products-pagination"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"a78b7a38-ec4b-04d1-dccd-1dbfaa859a86"},{"name":"busy.products.search – Products search","id":"14dcc96e-61bf-3256-ed8d-879507cc54ad","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"synthetic\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/products-search","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/products-search</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.products.search</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.products.search</code></strong> (BusyNotify <code>POST /v1/products-search</code>). The products matching the search fields; same rows, order and switches as <code>/products</code>. <strong>Read only.</strong></p>\n<p>Search fields (optional, combined with AND; trimmed; blank = no filter): <code>name</code>, <code>printName</code>, <code>alias</code>, <code>multipleAlias</code> (any of the 15 aliases), <code>groupName</code> — each \"contains\", ASCII case-insensitive, <strong><code>%</code> and <code>_</code> are wildcards</strong> (as the reference; no escape); <code>groupId</code> (positive number, equals the product's group). Quotes and SQL text are ordinary characters; values never enter a statement. No field = every product. <code>metadata.filters.search</code> echoes the applied fields.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5c.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","products-search"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"14dcc96e-61bf-3256-ed8d-879507cc54ad"},{"name":"busy.products-of-config.list – Optional product fields","id":"888af887-0b63-49d9-de63-d5dabb16be91","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/products-of-config","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/products-of-config</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.products-of-config.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.products-of-config.list</code></strong> (BusyNotify <code>POST /v1/products-of-config</code>). The optional product fields configured in BUSY (<code>Config</code> <code>RecType 2</code> / <code>79</code>, <code>Type 6</code>). <strong>Read only.</strong></p>\n<p>Request: <code>{ companyCode, financialYear }</code> only.</p>\n<p>Response (200): <code>data</code> = <code>[{ field_no (1–10), of_column (\"OF1\"…\"OF10\"), field_name (trimmed), field_type (\"Text\", \"List\", \"Amount\", \"Quantity\", \"Numeric\", \"Date\", \"Yes/No\" or \"\"), decimal_places (Numeric only, else null), maintain_master_database (Text only: \"Y\", \"N\" or \"\"; else \"\") }]</code>, only fields up to <code>NoOfFld</code> with a name, in field order. <code>metadata</code> as <strong>busy.branches.list – Branches</strong>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5c.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","products-of-config"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"888af887-0b63-49d9-de63-d5dabb16be91"},{"name":"busy.product-groups.hierarchy – Product group hierarchy","id":"a4a2020a-b1a9-bca1-d3a0-1d5b0a8f041d","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-groups-hierarchy","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/product-groups-hierarchy</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.product-groups.hierarchy</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.product-groups.hierarchy</code></strong> (BusyNotify <code>POST /v1/product-groups-hierarchy</code>). The product groups (<code>Master1</code>, <code>MasterType 5</code>) as a tree with direct and total product counts. <strong>Read only.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, rootGroupId? }</code> — <code>rootGroupId</code> optional, a positive JSON number: returns that group and its descendants; a code that is not a product group is <code>404 NOT_FOUND</code> (<code>field: rootGroupId</code>).</p>\n<p>Response (200): <code>data</code> = <code>{ root_group_id (the request's rootGroupId or null), hierarchy: [node] }</code>; node = <code>{ group_id, group_name, parent_group_id, direct_product_count, children: [node], descendant_group_ids (pre-order, itself first), total_product_count }</code>. Orphans (parent not a group), self-parents and groups without a parent are roots. Order: name (binary), then code. <code>metadata</code> adds <code>groupCount</code>, <code>rootCount</code>, <code>rowCount</code> (nodes), <code>maxDepth</code>.</p>\n<p>A multi-node cycle, a repeated group code or more than 500 levels is <code>422 BUSY_GROUP_HIERARCHY_INVALID</code> (no group values in the message).</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5d.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","product-groups-hierarchy"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"a4a2020a-b1a9-bca1-d3a0-1d5b0a8f041d"},{"name":"busy.products.multiple-prices – Product prices by category","id":"b4067ce2-25be-753a-65bc-f8828f560296","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"priceCategories\": [1, 2, 3]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/products-multiple-prices","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/products-multiple-prices</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.products.multiple-prices</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.products.multiple-prices</code></strong> (BusyNotify <code>POST /v1/products-multiple-prices</code>). Every product's sales price, MRP and discount per price category. <strong>Read only.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, priceCategories? }</code> — optional non-empty array of unique JSON numbers 1–26 (<code>400 INVALID_PARAMETER</code> otherwise; <code>\"1\"</code> or <code>1.5</code> is <code>400 BAD_REQUEST</code>); default 1–10; applied ascending.</p>\n<p>Response (200): <code>data</code> = <code>[{ product_id, product_name, {p}_product_sales_price, {p}_product_mrp, {p}_product_sales_discount … }]</code> with <code>{p}</code> = <code>a</code>…<code>z</code> for category 1–26: the largest <code>COALESCE(D1/D3/D2, 0)</code> of the product's <code>MasterSupport</code> rows with <code>I1 = 100 + category</code>, or all three <code>null</code> when it has none. Order: name (binary), then code. <code>metadata.priceCategories</code> = the applied categories.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5d.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","products-multiple-prices"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"b4067ce2-25be-753a-65bc-f8828f560296"},{"name":"busy.products.multiple-prices-datewise – Product prices by date","id":"a3c8cb64-60bd-98ce-4eef-4ebe5faee0c4","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/products-multiple-prices-datewise","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/products-multiple-prices-datewise</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.products.multiple-prices-datewise</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.products.multiple-prices-datewise</code></strong> (BusyNotify <code>POST /v1/products-multiple-prices-datewise</code>). Each product's prices at its latest pricing date. <strong>Read only.</strong></p>\n<p>Request: <code>{ companyCode, financialYear }</code> only.</p>\n<p>Response (200): <code>data</code> = the products with date-wise rows (<code>MasterSupport</code>, <code>I2 = 9</code>), by name (binary) then code: <code>{ product_id, product_name, latest_pricing_date (yyyy-MM-ddTHH:mm:ss[.ffffff]), a_price_identifier, a_product_sales_price, a_product_mrp, a_product_sales_discount, b_… }</code> — one set per identifier at that date (the largest <code>COALESCE(D1/D3/D2, 0)</code>), ordered by the identifier as an integer, prefixes <code>a</code> … <code>z</code>, <code>aa</code>, <code>ab</code> …. <code>metadata.latestPricingDate</code> is the date when every product shares one, else <code>null</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5d.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","products-multiple-prices-datewise"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"a3c8cb64-60bd-98ce-4eef-4ebe5faee0c4"},{"name":"busy.customers.list – Customers","id":"9d80f634-f5c4-a922-eeb5-0a8219613ffa","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"pendingSalesOrderOnly\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/customers","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/customers</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.customers.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.customers.list</code></strong> (BusyNotify <code>POST /v1/customers</code>). Every customer (<code>Master1</code>, <code>MasterType 2</code>) with contact, address, tax, group, salesman and balance fields. <strong>Read only. Personal data</strong> — never paste real rows into examples or tickets.</p>\n<p>Request: <code>{ companyCode, financialYear, pendingSalesOrderOnly? }</code> — a JSON boolean, default <code>false</code>; <code>true</code> keeps only customers of a sales order whose pending quantity (<code>ROUND(SUM(Tran3.Value1), 2)</code> per order) is above 0. <code>\"true\"</code> or <code>1</code> is <code>400 BAD_REQUEST</code>.</p>\n<p>Response (200): <code>data</code> = <code>[{ customer_id, customer_name, customer_alias, group_id, group_name, mobile_number, email_id, whatsapp_number, address_line_1..4, pin_code, country, state, gst_number, pan_number, station, opening_balance, balance, closing_balance, salesman_id, salesman_name, salesman_mobile_number, salesman_whatsapp_number, price_category }]</code>, by name (binary) then code. Balances: <code>ROUND(COALESCE(Folio1.D1, 0), 2)</code>, <code>ROUND(SUM(Tran2.Value1), 2)</code>, closing = rounded sum of both. WhatsApp numbers trimmed of spaces; everything else as stored. <code>metadata</code> adds <code>pendingSalesOrderOnly</code>, <code>rowCount</code>, <code>customerCount</code> (below <code>rowCount</code> only if BUSY repeats an address/opening row for a customer).</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5e.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","customers"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"9d80f634-f5c4-a922-eeb5-0a8219613ffa"},{"name":"busy.customers.get – Customer","id":"800faf6c-e304-a1e7-3def-27d5adcf3b48","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/customer","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/customer</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.customers.get</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.customers.get</code></strong> (BusyNotify <code>POST /v1/customer</code>). One customer by code, with exactly the fields of <em>Customers</em>. <strong>Read only. Personal data.</strong> Replace the synthetic <code>7001</code> with a real customer code.</p>\n<p>Request: <code>{ companyCode, financialYear, customerId }</code> — <code>customerId</code> a JSON integer 1–2147483647 (BUSY's 32-bit code); <code>\"1\"</code>, <code>1.5</code> → <code>400 BAD_REQUEST</code>; <code>0</code>, negative, larger → <code>400 INVALID_PARAMETER</code>.</p>\n<p>Response (200): <code>data</code> = a <strong>one-row array</strong> (the reference's shape); <code>metadata</code> adds <code>customerId</code>, <code>rowCount</code>. A code that is not a customer: <code>404 NOT_FOUND</code> (<code>field: customerId</code>). If BUSY holds two address or opening rows for the customer: <code>422 BUSY_DATA_INCONSISTENT</code> (never a silently chosen row).</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5e.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","customer"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"800faf6c-e304-a1e7-3def-27d5adcf3b48"},{"name":"busy.customer-groups.hierarchy – Customer group hierarchy","id":"af7672c1-02d7-66b7-d751-cfb682246a3e","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/customer-groups-hierarchy","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/customer-groups-hierarchy</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.customer-groups.hierarchy</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.customer-groups.hierarchy</code></strong> (BusyNotify <code>POST /v1/customer-groups-hierarchy</code>). The customer groups (<code>Master1</code>, <code>MasterType 1</code>) as a tree with direct and total customer counts — the same builder and rules as the product group hierarchy (<code>busy.product-groups.hierarchy</code>). <strong>Read only.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, rootGroupId? }</code> — a positive JSON integer: that group and its descendants; unknown → <code>404 NOT_FOUND</code> (<code>field: rootGroupId</code>).</p>\n<p>Response (200): <code>data</code> = <code>{ root_group_id, hierarchy: [node] }</code>; node = <code>{ group_id, group_name, parent_group_id, direct_customer_count, children, descendant_group_ids, total_customer_count }</code>. Orphans and self-parents are roots; name (binary) then code. A cycle, a repeated group code or more than 500 levels: <code>422 BUSY_GROUP_HIERARCHY_INVALID</code>. <code>metadata</code> adds <code>groupCount</code>, <code>rootCount</code>, <code>rowCount</code>, <code>maxDepth</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5e.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","customer-groups-hierarchy"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"af7672c1-02d7-66b7-d751-cfb682246a3e"},{"name":"busy.customers.validate-whatsapp – Validate WhatsApp","id":"8d705489-0205-02af-b63c-a79f31c84975","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"whatsappNumber\": \"+91 99999-99999\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/validate-whatsapp","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/validate-whatsapp</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>whatsappNumber</code> · operation <code>busy.customers.validate-whatsapp</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.customers.validate-whatsapp</code></strong> (BusyNotify <code>POST /v1/validate-whatsapp</code>). Whether a WhatsApp number belongs to one or more customers. <strong>Read only. Personal data</strong> — the example number is synthetic; the number you send is never logged or echoed.</p>\n<p>Request: <code>{ companyCode, financialYear, whatsappNumber }</code> — a JSON string. White space (spaces, tabs, non-breaking spaces …), <code>(</code>, <code>)</code>, <code>+</code> and <code>-</code> are removed; every other character is kept. Empty after that, or longer than 255 characters: <code>400 INVALID_PARAMETER</code>.</p>\n<p>Response (200): <code>data</code> = <code>{ isRegistered, matchedCustomers: [{ customer_id, customer_name, customer_alias, price_category, email_address, whatsapp_number }] }</code> — <strong>every</strong> customer whose stored number (spaces trimmed; spaces, <code>+</code>, <code>-</code>, <code>(</code>, <code>)</code> removed) equals it, by name then code. <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, matchCount, elapsedMs, executedAt</code> — no number, no customer.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5e.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","validate-whatsapp"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"8d705489-0205-02af-b63c-a79f31c84975"},{"name":"busy.customers.validate-email – Validate e-mail","id":"144cd0b0-5d14-6864-afca-f5d8d1c280b7","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"emailAddress\": \"synthetic@example.invalid\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/validate-email","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/validate-email</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>emailAddress</code> · operation <code>busy.customers.validate-email</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.customers.validate-email</code></strong> (BusyNotify <code>POST /v1/validate-email</code>). Whether an e-mail address belongs to one or more customers. <strong>Read only. Personal data</strong> — the example address is synthetic; the address you send is never logged or echoed.</p>\n<p>Request: <code>{ companyCode, financialYear, emailAddress }</code> — a JSON string, trimmed and lower-cased. Empty, not <code>name@domain.tld</code> without spaces (the reference's pattern), or longer than 255 characters: <code>400 INVALID_PARAMETER</code>.</p>\n<p>Response (200): <code>data</code> = <code>{ isRegistered, matchedCustomers: [{ customer_id, customer_name, customer_alias, price_category, email_address, whatsapp_number }] }</code> — <strong>every</strong> customer whose stored address (spaces trimmed, ASCII lower-case) equals it, by name then code. <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, matchCount, elapsedMs, executedAt</code> — no address, no customer.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5e.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","validate-email"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"144cd0b0-5d14-6864-afca-f5d8d1c280b7"},{"name":"busy.suppliers.list – Suppliers","id":"412aa3fc-3cab-5054-c40c-05b353c08d11","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/suppliers","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/suppliers</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.suppliers.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.suppliers.list</code></strong> (BusyNotify <code>POST /v1/suppliers</code>). Suppliers found from purchase activity. <strong>Read only. Supplier data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, supplierId?, search?, includeContactDetails?, page?, pageSize? }</code> — leave optional members out rather than sending them empty.</p>\n<ul>\n<li><code>supplierId</code>: JSON integer 1–2147483647.</li>\n<li><code>search</code>: text found in name, alias or print name (ASCII case-insensitive), at most 200 characters after trimming; never echoed.</li>\n<li><code>includeContactDetails</code>: JSON boolean, default <code>false</code>; only <code>true</code> returns <code>gst_number</code> and <code>mobile_number</code> (otherwise both <code>null</code>).</li>\n<li><code>page</code> from 1 (default 1), <code>pageSize</code> 1–500 (default 100).</li>\n</ul>\n<p>A supplier is an account master (type 2) named by a non-cancelled purchase (2), purchase-return (10) or purchase-order (13) voucher, or by a purchase-order trace. Cancelled = <code>Tran1.Cancelled</code>/<code>VchCancelled</code> reading 1/true/yes/y.</p>\n<p>Response (200): <code>data</code> = <code>[{ supplier_id, supplier_name, supplier_alias, supplier_print_name, supplier_group_id, supplier_group_name, purchase_voucher_count, purchase_return_voucher_count, purchase_order_count, has_purchase_vouchers, has_purchase_returns, has_purchase_orders, gst_number, mobile_number }]</code>, ordered by name (case-insensitive) then code. <code>metadata</code>: <code>apiVersion, operation, requestId, companyCode, financialYear, supplierId, searchApplied, includeContactDetails, page, pageSize, totalRows, rowCount, hasMore, elapsedMs, executedAt</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5h.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","suppliers"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"412aa3fc-3cab-5054-c40c-05b353c08d11"},{"name":"busy.optional-fields.definitions – Account and product optional fields","id":"606d482a-c3a8-452a-9cfe-a6a0fd350f18","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/optional-field-definitions","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/optional-field-definitions</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.optional-fields.definitions</code> · SQL Server and Access</p>\n<p><strong>Status:</strong> installed service-account acceptance passed 2026-10-17 (installed Host as <code>.\\AIZenySvc</code>, COMP0002 / FY 2026; answers equal to independent read-only SQL). No cloud route.</p>\n<hr />\n<p>The optional fields BUSY has defined for <strong>accounts</strong> and <strong>products (items)</strong> in one financial year (definitions are each year's BUSY setting), with each dropdown's existing values. Use it before sending <code>optionalFields</code> on the account and product writes.</p>\n<p><strong>Answer:</strong> <code>data</code> = <code>{ accounts: [field], products: [field] }</code>, <code>field</code> = <code>{ slot (\"OF1\"…\"OF10\"), name, kind (text | dropdown | number | date | yesNo | other), busyType, busySubDetail, decimalPlaces, writable, notWritableReason?, values? [{ code, name }] }</code> (values in BUSY's binary name order). <code>metadata</code> adds <code>accountFieldCount</code>, <code>productFieldCount</code>, <code>elapsedMs</code>.</p>\n<p><code>writable</code> follows the accepted scope: products — text, dropdown (existing values), whole-number, date, Yes/No; accounts — free text only. <strong>Account dropdown fields are listed but not writable</strong> (not proven in BUSY). AI Zeny never creates field definitions: define them in BUSY's own window.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> 5an; guide <code>docs/public/api/optional-fields.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","optional-field-definitions"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"aa21c8dd-9290-d913-a0d0-023d945ce735","name":"200 – definitions (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/optional-field-definitions","description":"**Local** · `POST {{baseUrl}}/api/v1/optional-field-definitions` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.optional-fields.definitions` · SQL Server and Access\n\n**Status:** installed service-account acceptance passed 2026-10-17 (installed Host as `.\\AIZenySvc`, COMP0002 / FY 2026; answers equal to independent read-only SQL). No cloud route.\n\n---\n\nThe optional fields BUSY has defined for **accounts** and **products (items)** in one financial year (definitions are each year's BUSY setting), with each dropdown's existing values. Use it before sending `optionalFields` on the account and product writes.\n\n**Answer:** `data` = `{ accounts: [field], products: [field] }`, `field` = `{ slot (\"OF1\"…\"OF10\"), name, kind (text | dropdown | number | date | yesNo | other), busyType, busySubDetail, decimalPlaces, writable, notWritableReason?, values? [{ code, name }] }` (values in BUSY's binary name order). `metadata` adds `accountFieldCount`, `productFieldCount`, `elapsedMs`.\n\n`writable` follows the accepted scope: products — text, dropdown (existing values), whole-number, date, Yes/No; accounts — free text only. **Account dropdown fields are listed but not writable** (not proven in BUSY). AI Zeny never creates field definitions: define them in BUSY's own window.\n\nContract: `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"accounts\": [\n      { \"slot\": \"OF1\", \"name\": \"Region\", \"kind\": \"dropdown\", \"busyType\": 1, \"busySubDetail\": 2, \"decimalPlaces\": null, \"writable\": false,\n        \"notWritableReason\": \"Account dropdown fields are not supported yet: BUSY's account value lists were not proven (a dedicated test is pending). Set the value in BUSY.\",\n        \"values\": [ { \"code\": 7301, \"name\": \"Synthetic North\" } ] },\n      { \"slot\": \"OF2\", \"name\": \"Contact note\", \"kind\": \"text\", \"busyType\": 1, \"busySubDetail\": 1, \"decimalPlaces\": null, \"writable\": true }\n    ],\n    \"products\": [\n      { \"slot\": \"OF1\", \"name\": \"Brand\", \"kind\": \"dropdown\", \"busyType\": 1, \"busySubDetail\": 2, \"decimalPlaces\": null, \"writable\": true,\n        \"values\": [ { \"code\": 7311, \"name\": \"Synthetic Acme\" }, { \"code\": 7312, \"name\": \"Synthetic Nova\" } ] },\n      { \"slot\": \"OF2\", \"name\": \"Shade\", \"kind\": \"text\", \"busyType\": 1, \"busySubDetail\": 1, \"decimalPlaces\": null, \"writable\": true },\n      { \"slot\": \"OF3\", \"name\": \"Pack count\", \"kind\": \"number\", \"busyType\": 5, \"busySubDetail\": 0, \"decimalPlaces\": 0, \"writable\": true },\n      { \"slot\": \"OF4\", \"name\": \"Launch date\", \"kind\": \"date\", \"busyType\": 6, \"busySubDetail\": 0, \"decimalPlaces\": null, \"writable\": true },\n      { \"slot\": \"OF5\", \"name\": \"Seasonal\", \"kind\": \"yesNo\", \"busyType\": 7, \"busySubDetail\": 0, \"decimalPlaces\": null, \"writable\": true }\n    ]\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.optional-fields.definitions\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e21\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"accountFieldCount\": 2,\n    \"productFieldCount\": 5,\n    \"elapsedMs\": 42\n  }\n}"}],"_postman_id":"606d482a-c3a8-452a-9cfe-a6a0fd350f18"}],"id":"daa9d9d1-dc51-4afd-9ee6-348466fbc6db","description":"<p>BUSY masters read straight from the company's database: units, branches, categories, groups, material centres, sale types, salesmen, voucher series, parameters, products, prices and hierarchies, customers and suppliers. Read only. Body: <code>companyCode</code>, <code>financialYear</code> plus each operation's own members. These are POST requests only because they carry a JSON body; none of them changes BUSY or AI Zeny.</p>\n","_postman_id":"daa9d9d1-dc51-4afd-9ee6-348466fbc6db","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Accounting & Reports (read only)","item":[{"name":"busy.customers.dashboard – Customer dashboard","id":"0d65a5e3-8879-9bdc-9a5a-3d772c83951d","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/customer-dashboard","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/customer-dashboard</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.customers.dashboard</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.customers.dashboard</code></strong> (BusyNotify <code>POST /v1/customer-dashboard</code>). One customer's balances, receivables and sales totals. <strong>Read only. Financial data.</strong> Replace the synthetic <code>7001</code> with a customer code.</p>\n<p>Request: <code>{ companyCode, financialYear, customerId }</code> — <code>customerId</code> a JSON integer 1–2147483647.</p>\n<p>Response (200): <code>data</code> = one object <code>{ customer_id, customer_name, customer_print_name, closing_balance, pending_balance, due_balance, credit_limit, total_sales_amount, total_receipts_amount, total_sale_returns_amount }</code> (numbers, 0 when none). Pending = <code>ABS(SUM(Tran3.Value1))</code> per eligible bill reference (types 1/9 negative, 3/16 positive); due = on or before <code>metadata.calculationDate</code> (the UTC calendar date of the request). Not a customer: <code>404 NOT_FOUND</code> (<code>field: customerId</code>); a repeated master row: <code>422 BUSY_DATA_INCONSISTENT</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5f.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","customer-dashboard"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"0d65a5e3-8879-9bdc-9a5a-3d772c83951d"},{"name":"busy.customers.pending-bills – Customers with pending bills","id":"7d1ea91d-5e8f-5897-1d09-e637623d6754","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/customers-pending-bills","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/customers-pending-bills</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.customers.pending-bills</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.customers.pending-bills</code></strong> (BusyNotify <code>POST /v1/customers-pending-bills</code>). Customers with a pending bill balance and a non-blank WhatsApp number. <strong>Read only. Personal and financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear }</code> only.</p>\n<p>Response (200): <code>data</code> = <code>[{ customer_id, customer_name, customer_alias, group_id, group_name, mobile_number, email_id, whatsapp_number, address_line_1..4, pin_code, country, state, gst_number, pan_number, station, opening_balance, balance, closing_balance, salesman_id, salesman_name, salesman_mobile_number, salesman_whatsapp_number, price_category, total_pending_amount, total_due_amount }]</code> — the complete <code>busy.customers.list</code> customer row (<code>customer_alias</code> = <code>Master1.Alias</code> as stored: null stays null, empty stays \"\") followed by the two totals (28 members), by name then code. <code>metadata</code> adds <code>calculationDate</code>, <code>rowCount</code>, <code>customerCount</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5f.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","customers-pending-bills"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"7d1ea91d-5e8f-5897-1d09-e637623d6754"},{"name":"busy.customers.bills.pending – Customer pending bills","id":"a1d3b347-d83f-f545-2ab9-78c02c7984e9","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"isDue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/customer-pending-bills","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/customer-pending-bills</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.customers.bills.pending</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.customers.bills.pending</code></strong> (BusyNotify <code>POST /v1/customer-pending-bills</code>). One customer's pending bills. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, customerId, isDue? }</code> — <code>isDue</code> a JSON boolean (default <code>false</code>); <code>true</code> keeps bills due on or before <code>metadata.calculationDate</code> (UTC today). <code>1</code>/<code>0</code>/<code>\"true\"</code> are <code>400 BAD_REQUEST</code>.</p>\n<p>Response (200): <code>data</code> = <code>[{ user_id, account_name, salesman_code, transaction_date, transaction_date_raw, transaction_type, reference_number, invoice_number, total_reference_amount, total_pending_amount, is_due (\"YES\"/\"NO\"), due_date, due_date_raw, days_until_due, days_overdue }]</code>, ordered by days until due (none first), bill date, reference number. An unknown customer answers an empty list (as the reference).</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5f.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","customer-pending-bills"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"a1d3b347-d83f-f545-2ab9-78c02c7984e9"},{"name":"busy.customers.bills.statement – Customer bill-wise statement","id":"f745193b-1307-c28b-09bd-0c5767b581a4","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/customer-bill-wise-statement","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/customer-bill-wise-statement</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.customers.bills.statement</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.customers.bills.statement</code></strong> (BusyNotify <code>POST /v1/customer-bill-wise-statement</code>). One customer's open bill references. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, customerId }</code>.</p>\n<p>Response (200): <code>data</code> = <code>[{ reference_number, transaction_type, transaction_date, transaction_date_raw, total_reference_amount, receivable_amount, payable_amount, due_date, due_date_raw, due_days, ref_code, voucher_code, voucher_type, voucher_series_code, signed_balance }]</code> over <code>Tran3</code> rows of record type 1, method 1, <code>MasterCode2 = 0</code>, approval status not 2; a negative signed balance is receivable, a positive one payable (the other null); references balancing to 0 are left out. <code>due_days</code> = calculation date minus due date (negative when not yet due). Labels: 1 OpBl, 3 Sale Return, 9 Sale, 14 Receipt, 16 Journal, 17 Debit Note, 18 Credit Note, 19 Payment, else <code>VchType-{n}</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5f.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","customer-bill-wise-statement"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"f745193b-1307-c28b-09bd-0c5767b581a4"},{"name":"busy.customers.ledger – Customer ledger","id":"597cd151-4e2d-4dae-5ad9-4e63fc65206c","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"startDate\": \"\",\n  \"endDate\": \"\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/customer-ledger","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/customer-ledger</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.customers.ledger</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.customers.ledger</code></strong> (BusyNotify <code>POST /v1/customer-ledger</code>). One customer's ledger over one or more financial years. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, customerId, additionalFinancialYear?, startDate?, endDate? }</code>.</p>\n<ul>\n<li><code>additionalFinancialYear</code> (optional, leave it out for one year): a JSON <strong>string</strong> of four-digit years separated by commas, e.g. <code>\"2025\"</code> or <code>\"2024,2025\"</code>. Trimmed, blanks dropped, each year once, the primary first. A string with no year (<code>\"\"</code>) or anything but four-digit years is <code>400 INVALID_PARAMETER</code>; an array is <code>400 BAD_REQUEST</code>. Every year must be allowed for the company; one refused or unreadable year fails the whole request (no partial answer).</li>\n<li><code>startDate</code> / <code>endDate</code>: <code>YYYY-MM-DD</code> only (real dates; <code>\"\"</code> = no bound). Lines before <code>startDate</code> move into each year's opening balance; <code>startDate</code> after <code>endDate</code> is <code>400 INVALID_PARAMETER</code>.</li>\n</ul>\n<p>Response (200): <code>data</code> = <code>[{ user_id, opening_balance, user_id2, transaction_date_iso, formatted_date, voucher_type, voucher_no, account_name, debit, credit, voucher_code, on_account, financial_year }]</code> — the customer's <code>Tran2</code> record-type-1 lines, per year ordered by voucher code, date, line; opening = <code>ROUND(every Folio1 row + lines before startDate, 2)</code>; <code>account_name</code> = the largest opposite-sign counter-party; <code>user_id2</code> = that party, else the voucher's other party with the lowest line number; <code>on_account</code> = <code>Y</code> for types 14/19 without a bill trace. An unknown code returns <code>data: []</code>.</p>\n<p><code>metadata</code>: <code>apiVersion, operation, requestId, companyCode, financialYear, financialYears, customerId, startDate, endDate, rowCount, elapsedMs, executedAt</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5g.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","customer-ledger"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"597cd151-4e2d-4dae-5ad9-4e63fc65206c"},{"name":"busy.suppliers.ledger – Supplier ledger","id":"6dd230e4-51cb-17d2-a14d-21c265438f3a","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"supplierId\": {{supplierId}},\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/supplier-ledger","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/supplier-ledger</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>supplierId</code> · operation <code>busy.suppliers.ledger</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.suppliers.ledger</code></strong> (BusyNotify <code>POST /v1/supplier-ledger</code>). One supplier's ledger. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, supplierId, fromDate?, toDate?, page?, pageSize? }</code> — <code>supplierId</code> required (JSON integer 1–2147483647); <code>fromDate</code>/<code>toDate</code> <code>YYYY-MM-DD</code> real dates inside the financial year (default 1 April – 31 March), <code>fromDate</code> not after <code>toDate</code>; leave optional members out rather than sending them empty. <code>page</code> from 1, <code>pageSize</code> 1–500 (default 100).</p>\n<p>Response (200): <code>data</code> = <code>{ rows, summary }</code>.</p>\n<ul>\n<li><code>rows[]</code>: <code>ledger_row_id</code> (the row's position in the year's ordered ledger), <code>voucher_code, voucher_type_id, voucher_number, voucher_date, line_number, supplier_name, supplier_id, financial_year_opening_balance, debit, credit, running_balance</code> — <code>Tran2</code> record-type-1 lines of non-cancelled vouchers, ordered by date, voucher, line; the running balance includes every earlier line of the year, so it is correct on any page.</li>\n<li><code>summary</code> (never per page): <code>financial_year_opening_balance</code> (every Folio1 row), <code>period_opening_balance</code> (+ lines before fromDate), <code>period_debit</code>, <code>period_credit</code>, <code>closing_balance</code>.\nAn unknown code returns no rows and a summary of its opening only.</li>\n</ul>\n<p><code>metadata</code>: <code>apiVersion, operation, requestId, companyCode, financialYear, supplierId, fromDate, toDate, page, pageSize, totalRows, rowCount, hasMore, elapsedMs, executedAt</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5h.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","supplier-ledger"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"6dd230e4-51cb-17d2-a14d-21c265438f3a"},{"name":"busy.suppliers.bills.pending – Supplier pending bills","id":"3f30c52f-d286-a129-3f35-888dea0abca5","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"status\": \"open\",\n  \"includeCredits\": true,\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/supplier-pending-bills","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/supplier-pending-bills</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.suppliers.bills.pending</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.suppliers.bills.pending</code></strong> (BusyNotify <code>POST /v1/supplier-pending-bills</code>). Supplier bills with allocations, and on-account supplier credits. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, supplierId?, status?, includeCredits?, asOfDate?, page?, pageSize? }</code> — leave optional members out rather than sending them empty.</p>\n<ul>\n<li><code>supplierId</code>: JSON integer 1–2147483647; default every supplier.</li>\n<li><code>status</code>: <code>open</code> (pending ≠ 0, default), <code>closed</code> (= 0) or <code>all</code>.</li>\n<li><code>includeCredits</code>: JSON boolean, default <code>true</code>; <code>false</code> leaves out every row with a negative pending amount.</li>\n<li><code>asOfDate</code>: <code>YYYY-MM-DD</code> inside the financial year; default today (UTC) within the year.</li>\n<li><code>page</code> from 1, <code>pageSize</code> 1–500 (default 100).</li>\n</ul>\n<p>Bills are matched by the exact supplier and BUSY <code>Tran3.RefCode</code> (no FIFO, never another supplier's row, cancelled rows left out); <code>pending_amount</code> sums every row of that reference up to the as-of date. On-account credits are separate rows with <code>bill_reference_code: null</code>, <code>status: \"Credit\"</code>, <code>is_unadjusted_credit: 1</code>, <code>allocations: []</code>.</p>\n<p>Response (200): <code>data</code> = <code>[{ supplier_id, supplier_name, bill_reference_code, reference_number, origin_voucher_code, origin_voucher_type_id, bill_date, due_date, original_amount, pending_amount, allocation_count, allocated_amount, status (Payable|Credit|Closed), days_overdue, is_unadjusted_credit, allocations: [{ voucher_code, voucher_type_id, voucher_number, allocation_date, amount, signed_amount, bill_reference_code, bill_reference_number }] }]</code>. <code>metadata</code>: <code>apiVersion, operation, requestId, companyCode, financialYear, supplierId, status, includeCredits, asOfDate, page, pageSize, totalRows, rowCount, hasMore, elapsedMs, executedAt</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5h.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","supplier-pending-bills"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"3f30c52f-d286-a129-3f35-888dea0abca5"},{"name":"busy.items.ledger – Single item ledger","id":"dde695be-69c8-fc52-7c09-28b48aa86f77","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": {{productId}},\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/single-item-ledger","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/single-item-ledger</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>productId</code> · operation <code>busy.items.ledger</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.items.ledger</code></strong> (BusyNotify <code>POST /v1/single-item-ledger</code>). One product's stock ledger: opening (opening stock <code>Folio1</code> plus every line before <code>fromDate</code>), every inward and outward stock line (record type 2, every voucher type except stock transfer) with its running balance, closing values and the <code>Tran4</code> control totals. <strong>Read only. Stock and amount data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, productId, fromDate?, toDate?, page?, pageSize? }</code> — <code>productId</code> required (1–2147483647); dates <code>YYYY-MM-DD</code> inside the financial year, by default the whole year. Pages: default 1 / 100, maximum 500.</p>\n<p>The balances and the summary are computed over the whole range before the page is cut: they never depend on the page. A code that is not a product is <code>404 NOT_FOUND</code> (<code>field: productId</code>).</p>\n<p>Response (200): <code>data</code> = <code>{ product: { product_id, product_name, product_alias, product_group_id, product_group_name, unit_id, unit_name }, summary: { opening_quantity, opening_amount, quantity_in, amount_in, quantity_out, amount_out, closing_quantity, closing_amount, tran4_control_quantity, tran4_control_amount }, ledger: [{ date, voucher_type, voucher_type_id, voucher_number, voucher_code, sr_no, party_id, party_name, material_center_id, material_center_name, particulars, quantity_in, amount_in, quantity_out, amount_out, balance_quantity, balance_amount }] }</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5l.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","single-item-ledger"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"33de6bf4-45a6-8d1c-e41b-b25b10796dc5","name":"200 – synthetic item ledger","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": {{productId}},\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/single-item-ledger","description":"**Local** · `POST {{baseUrl}}/api/v1/single-item-ledger` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear`, `productId` · operation `busy.items.ledger`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.items.ledger`** (BusyNotify `POST /v1/single-item-ledger`). One product's stock ledger: opening (opening stock `Folio1` plus every line before `fromDate`), every inward and outward stock line (record type 2, every voucher type except stock transfer) with its running balance, closing values and the `Tran4` control totals. **Read only. Stock and amount data.**\n\nRequest: `{ companyCode, financialYear, productId, fromDate?, toDate?, page?, pageSize? }` — `productId` required (1–2147483647); dates `YYYY-MM-DD` inside the financial year, by default the whole year. Pages: default 1 / 100, maximum 500.\n\nThe balances and the summary are computed over the whole range before the page is cut: they never depend on the page. A code that is not a product is `404 NOT_FOUND` (`field: productId`).\n\nResponse (200): `data` = `{ product: { product_id, product_name, product_alias, product_group_id, product_group_name, unit_id, unit_name }, summary: { opening_quantity, opening_amount, quantity_in, amount_in, quantity_out, amount_out, closing_quantity, closing_amount, tran4_control_quantity, tran4_control_amount }, ledger: [{ date, voucher_type, voucher_type_id, voucher_number, voucher_code, sr_no, party_id, party_name, material_center_id, material_center_name, particulars, quantity_in, amount_in, quantity_out, amount_out, balance_quantity, balance_amount }] }`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5l."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"product\":{\"product_id\":9401,\"product_name\":\"Synthetic Item\",\"product_alias\":\"SI\",\"product_group_id\":9501,\"product_group_name\":\"Synthetic Item Group\",\"unit_id\":9701,\"unit_name\":\"Pcs\"},\"summary\":{\"opening_quantity\":14.5,\"opening_amount\":1305.25,\"quantity_in\":7.25,\"amount_in\":652.61,\"quantity_out\":3.5,\"amount_out\":315.07,\"closing_quantity\":18.25,\"closing_amount\":1642.79,\"tran4_control_quantity\":18.25,\"tran4_control_amount\":1642.79},\"ledger\":[{\"date\":\"05-06-2025\",\"voucher_type\":\"Purc\",\"voucher_type_id\":2,\"voucher_number\":\"SYN/P/0001\",\"voucher_code\":97611,\"sr_no\":1,\"party_id\":7101,\"party_name\":\"Synthetic Supplier\",\"material_center_id\":9601,\"material_center_name\":\"Synthetic Store\",\"particulars\":\"Synthetic Supplier\",\"quantity_in\":7.25,\"amount_in\":652.61,\"quantity_out\":0,\"amount_out\":0,\"balance_quantity\":21.75,\"balance_amount\":1957.86},{\"date\":\"12-06-2025\",\"voucher_type\":\"Sale\",\"voucher_type_id\":9,\"voucher_number\":\"SYN/S/0001\",\"voucher_code\":97561,\"sr_no\":1,\"party_id\":7001,\"party_name\":\"Synthetic Customer\",\"material_center_id\":9601,\"material_center_name\":\"Synthetic Store\",\"particulars\":\"Synthetic Customer\",\"quantity_in\":0,\"amount_in\":0,\"quantity_out\":3.5,\"amount_out\":315.07,\"balance_quantity\":18.25,\"balance_amount\":1642.79}]},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.items.ledger\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"productId\":9401,\"fromDate\":\"2025-06-01\",\"toDate\":\"2025-06-30\",\"page\":1,\"pageSize\":100,\"totalRows\":2,\"rowCount\":2,\"hasMore\":false,\"elapsedMs\":17,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"dde695be-69c8-fc52-7c09-28b48aa86f77"},{"name":"busy.sales-analysis.item – Sales analysis: one item","id":"931c50c6-7ea7-b8b6-e2eb-714be4c3588b","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": {{productId}},\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-analysis-single-item","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/sales-analysis-single-item</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>productId</code> · operation <code>busy.sales-analysis.item</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.sales-analysis.item</code></strong> (BusyNotify <code>POST /v1/sales-analysis-single-item</code>). One product's sales and returns per customer: quantities, amounts, net values, average price and voucher counts, with a summary over the whole range. Only sale types whose <code>B18</code>/<code>B15</code> flags are not set count. <strong>One classification for all three analyses:</strong> a sale-voucher line without the return flag is a sale; a sales-return voucher line, or a sale-voucher line with <code>IsReturnQty</code> set (true, 1, -1), is a return — never both, subtracted once (owner correction: the reference ignored the flagged line here). <strong>Read only. Customer and amount data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, productId, fromDate?, toDate?, page?, pageSize? }</code> — dates default to the whole financial year. Pages: default 1 / 100, maximum 500; the summary never depends on the page. A code that is not a product is <code>404 NOT_FOUND</code>.</p>\n<p>Response (200): <code>data</code> = <code>{ item: { product_id, product_name, product_alias, product_group_id, product_group_name, unit }, rows: [{ customer_id, customer_name, sale_quantity, return_quantity, net_sale_quantity, unit, sale_amount, return_amount, net_sale_amount, average_price, sale_voucher_count, sale_return_voucher_count }], summary: { sale_quantity_total, return_quantity_total, net_sale_quantity_total, sale_amount_total, return_amount_total, net_sale_amount_total, average_price_total } }</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5l.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","sales-analysis-single-item"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"08645229-1cf9-16ef-a935-92c968ee5eb3","name":"200 – synthetic single-item analysis","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": {{productId}},\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-analysis-single-item","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-analysis-single-item` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear`, `productId` · operation `busy.sales-analysis.item`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.sales-analysis.item`** (BusyNotify `POST /v1/sales-analysis-single-item`). One product's sales and returns per customer: quantities, amounts, net values, average price and voucher counts, with a summary over the whole range. Only sale types whose `B18`/`B15` flags are not set count. **One classification for all three analyses:** a sale-voucher line without the return flag is a sale; a sales-return voucher line, or a sale-voucher line with `IsReturnQty` set (true, 1, -1), is a return — never both, subtracted once (owner correction: the reference ignored the flagged line here). **Read only. Customer and amount data.**\n\nRequest: `{ companyCode, financialYear, productId, fromDate?, toDate?, page?, pageSize? }` — dates default to the whole financial year. Pages: default 1 / 100, maximum 500; the summary never depends on the page. A code that is not a product is `404 NOT_FOUND`.\n\nResponse (200): `data` = `{ item: { product_id, product_name, product_alias, product_group_id, product_group_name, unit }, rows: [{ customer_id, customer_name, sale_quantity, return_quantity, net_sale_quantity, unit, sale_amount, return_amount, net_sale_amount, average_price, sale_voucher_count, sale_return_voucher_count }], summary: { sale_quantity_total, return_quantity_total, net_sale_quantity_total, sale_amount_total, return_amount_total, net_sale_amount_total, average_price_total } }`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5l."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"item\":{\"product_id\":9401,\"product_name\":\"Synthetic Item\",\"product_alias\":\"SI\",\"product_group_id\":9501,\"product_group_name\":\"Synthetic Item Group\",\"unit\":\"Pcs\"},\"rows\":[{\"customer_id\":7001,\"customer_name\":\"Synthetic Customer\",\"sale_quantity\":7.25,\"return_quantity\":1.5,\"net_sale_quantity\":5.75,\"unit\":\"Pcs\",\"sale_amount\":1005.34,\"return_amount\":208.02,\"net_sale_amount\":797.32,\"average_price\":138.66,\"sale_voucher_count\":1,\"sale_return_voucher_count\":1}],\"summary\":{\"sale_quantity_total\":7.25,\"return_quantity_total\":1.5,\"net_sale_quantity_total\":5.75,\"sale_amount_total\":1005.34,\"return_amount_total\":208.02,\"net_sale_amount_total\":797.32,\"average_price_total\":138.66}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.sales-analysis.item\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"productId\":9401,\"fromDate\":\"2025-04-01\",\"toDate\":\"2026-03-31\",\"page\":1,\"pageSize\":100,\"totalRows\":1,\"rowCount\":1,\"hasMore\":false,\"elapsedMs\":14,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"931c50c6-7ea7-b8b6-e2eb-714be4c3588b"},{"name":"busy.sales-analysis.customer – Sales analysis: one customer","id":"71badc6f-026e-3cd3-fc55-663e82745643","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-analysis-single-customer","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/sales-analysis-single-customer</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.sales-analysis.customer</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.sales-analysis.customer</code></strong> (BusyNotify <code>POST /v1/sales-analysis-single-customer</code>). One customer's sales and sales returns per product in main and alternative units: quantities, amounts, net values, average prices and voucher counts, with a summary over the whole range. A return is a sales-return voucher (type 3) or a return flagged inside a sale voucher; each is subtracted once. <strong>Read only. Customer and amount data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, customerId, fromDate?, toDate?, page?, pageSize? }</code> — dates default to the whole financial year. Pages: default 1 / 100, maximum 500; the summary never depends on the page. A code that is not a customer is <code>404 NOT_FOUND</code>.</p>\n<p>Response (200): <code>data</code> = <code>{ customer: { customer_id, customer_name, customer_alias }, rows: [20-member product rows], summary: { sale_quantity_main_total, sale_quantity_alternative_total, return_quantity_main_total, return_quantity_alternative_total, net_sale_quantity_main_total, net_sale_quantity_alternative_total, sale_amount_total, return_amount_total, net_sale_amount_total, average_price_main_total, average_price_alternative_total } }</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5l.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","sales-analysis-single-customer"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"19a9245a-e654-e117-e14c-1fdd1d0caf12","name":"200 – synthetic single-customer analysis","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-analysis-single-customer","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-analysis-single-customer` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear`, `customerId` · operation `busy.sales-analysis.customer`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.sales-analysis.customer`** (BusyNotify `POST /v1/sales-analysis-single-customer`). One customer's sales and sales returns per product in main and alternative units: quantities, amounts, net values, average prices and voucher counts, with a summary over the whole range. A return is a sales-return voucher (type 3) or a return flagged inside a sale voucher; each is subtracted once. **Read only. Customer and amount data.**\n\nRequest: `{ companyCode, financialYear, customerId, fromDate?, toDate?, page?, pageSize? }` — dates default to the whole financial year. Pages: default 1 / 100, maximum 500; the summary never depends on the page. A code that is not a customer is `404 NOT_FOUND`.\n\nResponse (200): `data` = `{ customer: { customer_id, customer_name, customer_alias }, rows: [20-member product rows], summary: { sale_quantity_main_total, sale_quantity_alternative_total, return_quantity_main_total, return_quantity_alternative_total, net_sale_quantity_main_total, net_sale_quantity_alternative_total, sale_amount_total, return_amount_total, net_sale_amount_total, average_price_main_total, average_price_alternative_total } }`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5l."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"customer\":{\"customer_id\":7001,\"customer_name\":\"Synthetic Customer\",\"customer_alias\":\"SC\"},\"rows\":[{\"product_id\":9401,\"product_name\":\"Synthetic Item\",\"product_alias\":\"SI\",\"product_group_id\":9501,\"product_group_name\":\"Synthetic Item Group\",\"main_unit\":\"Pcs\",\"alternative_unit\":\"Box\",\"sale_quantity_main\":7.25,\"sale_quantity_alternative\":0.73,\"return_quantity_main\":1.5,\"return_quantity_alternative\":0.15,\"net_sale_quantity_main\":5.75,\"net_sale_quantity_alternative\":0.58,\"sale_amount\":1005.34,\"return_amount\":208.02,\"net_sale_amount\":797.32,\"average_price_main\":138.66,\"average_price_alternative\":1374.69,\"sale_voucher_count\":1,\"sale_return_voucher_count\":1}],\"summary\":{\"sale_quantity_main_total\":7.25,\"sale_quantity_alternative_total\":0.73,\"return_quantity_main_total\":1.5,\"return_quantity_alternative_total\":0.15,\"net_sale_quantity_main_total\":5.75,\"net_sale_quantity_alternative_total\":0.58,\"sale_amount_total\":1005.34,\"return_amount_total\":208.02,\"net_sale_amount_total\":797.32,\"average_price_main_total\":138.66,\"average_price_alternative_total\":1374.69}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.sales-analysis.customer\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"customerId\":7001,\"fromDate\":\"2025-04-01\",\"toDate\":\"2026-03-31\",\"page\":1,\"pageSize\":100,\"totalRows\":1,\"rowCount\":1,\"hasMore\":false,\"elapsedMs\":12,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"71badc6f-026e-3cd3-fc55-663e82745643"},{"name":"busy.customers.product-analytics – Customer product analytics","id":"99700517-cb14-5d58-2275-8349456bdf24","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/customer-product-analytics","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/customer-product-analytics</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.customers.product-analytics</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.customers.product-analytics</code></strong> (BusyNotify <code>POST /v1/customer-product-analytics</code>). One customer's active products (a sale or return in the period) and dropped products (only earlier sales) over one or more financial years: sales, returns, net quantities and amounts, taxable, GST/CGST/SGST/IGST, invoice counts, purchase rates (last, average, min, max, weighted), first/last purchase, days since the last purchase, purchase frequency and interval, and daily, ISO-week and monthly trends. <strong>Read only. Customer and amount data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, customerId, additionalFinancialYear?, fromDate?, toDate?, page?, pageSize? }</code>.</p>\n<ul>\n<li><code>additionalFinancialYear</code>: optional, comma-separated four-digit years (for example <code>\"2024\"</code>); trimmed, each once, the primary year first. <strong>Every year is checked before any read; one refused or unreadable year fails the whole request.</strong></li>\n<li>Dates default to the primary year; every financial year the period touches must be requested. Lines before <code>fromDate</code> are purchase history; nothing after <code>toDate</code> counts.</li>\n<li>Pages: the products are one sequence — active products (highest net sale amount first), then dropped products (latest purchase first) — paged together (default 1 / 100, maximum 500). The summary and the classification never depend on the page.</li>\n</ul>\n<p>Response (200): <code>data</code> = <code>{ customer, summary, active_products, dropped_products }</code>. A code that is not a customer is <code>404 NOT_FOUND</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5l.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","customer-product-analytics"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"f868e666-f5f4-b855-e20c-8b1ec106ecca","name":"200 – synthetic analytics (with additionalFinancialYear \"2024\")","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/customer-product-analytics","description":"**Local** · `POST {{baseUrl}}/api/v1/customer-product-analytics` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear`, `customerId` · operation `busy.customers.product-analytics`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.customers.product-analytics`** (BusyNotify `POST /v1/customer-product-analytics`). One customer's active products (a sale or return in the period) and dropped products (only earlier sales) over one or more financial years: sales, returns, net quantities and amounts, taxable, GST/CGST/SGST/IGST, invoice counts, purchase rates (last, average, min, max, weighted), first/last purchase, days since the last purchase, purchase frequency and interval, and daily, ISO-week and monthly trends. **Read only. Customer and amount data.**\n\nRequest: `{ companyCode, financialYear, customerId, additionalFinancialYear?, fromDate?, toDate?, page?, pageSize? }`.\n- `additionalFinancialYear`: optional, comma-separated four-digit years (for example `\"2024\"`); trimmed, each once, the primary year first. **Every year is checked before any read; one refused or unreadable year fails the whole request.**\n- Dates default to the primary year; every financial year the period touches must be requested. Lines before `fromDate` are purchase history; nothing after `toDate` counts.\n- Pages: the products are one sequence — active products (highest net sale amount first), then dropped products (latest purchase first) — paged together (default 1 / 100, maximum 500). The summary and the classification never depend on the page.\n\nResponse (200): `data` = `{ customer, summary, active_products, dropped_products }`. A code that is not a customer is `404 NOT_FOUND`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5l."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"customer\":{\"customer_id\":7001,\"customer_name\":\"Synthetic Customer\",\"customer_alias\":\"SC\"},\"summary\":{\"total_product_count\":2,\"active_product_count\":1,\"dropped_product_count\":1,\"sale_quantity_main_total\":7.25,\"sale_quantity_alternative_total\":0.73,\"return_quantity_main_total\":1.5,\"return_quantity_alternative_total\":0.15,\"net_sale_quantity_main_total\":5.75,\"net_sale_quantity_alternative_total\":0.58,\"sale_amount_total\":1005.34,\"return_amount_total\":208.02,\"net_sale_amount_total\":797.32,\"taxable_amount_total\":797.32,\"gst_amount_total\":143.52,\"cgst_amount_total\":71.76,\"sgst_amount_total\":71.76,\"igst_amount_total\":0,\"sale_invoice_count_total\":1,\"sale_return_invoice_count_total\":1},\"active_products\":[{\"product_id\":9401,\"product_name\":\"Synthetic Item\",\"product_alias\":\"SI\",\"product_group_id\":9501,\"product_group_name\":\"Synthetic Item Group\",\"main_unit\":\"Pcs\",\"alternative_unit\":\"Box\",\"product_status\":\"active\",\"sale_quantity_main\":7.25,\"sale_quantity_alternative\":0.73,\"return_quantity_main\":1.5,\"return_quantity_alternative\":0.15,\"net_sale_quantity_main\":5.75,\"net_sale_quantity_alternative\":0.58,\"sale_amount\":1005.34,\"return_amount\":208.02,\"net_sale_amount\":797.32,\"taxable_amount\":797.32,\"gst_amount\":143.52,\"cgst_amount\":71.76,\"sgst_amount\":71.76,\"igst_amount\":0,\"sale_invoice_count\":1,\"sale_return_invoice_count\":1,\"last_purchase_rate\":138.67,\"average_rate\":138.67,\"min_rate\":138.67,\"max_rate\":138.67,\"weighted_average_rate\":138.67,\"first_purchase_date\":\"2025-06-02\",\"last_purchase_date\":\"2025-06-02\",\"days_since_last_purchase\":302,\"purchase_frequency_count\":1,\"average_purchase_interval_days\":0,\"daily_trend\":[{\"period\":\"2025-06-02\",\"sale_quantity_main\":7.25,\"net_sale_quantity_main\":7.25,\"net_sale_amount\":1005.34,\"sale_invoice_count\":1},{\"period\":\"2025-06-20\",\"sale_quantity_main\":0,\"net_sale_quantity_main\":-1.5,\"net_sale_amount\":-208.02,\"sale_invoice_count\":0}],\"weekly_trend\":[{\"period\":\"2025-W23\",\"sale_quantity_main\":7.25,\"net_sale_quantity_main\":7.25,\"net_sale_amount\":1005.34,\"sale_invoice_count\":1},{\"period\":\"2025-W25\",\"sale_quantity_main\":0,\"net_sale_quantity_main\":-1.5,\"net_sale_amount\":-208.02,\"sale_invoice_count\":0}],\"monthly_trend\":[{\"period\":\"2025-06\",\"sale_quantity_main\":7.25,\"net_sale_quantity_main\":5.75,\"net_sale_amount\":797.32,\"sale_invoice_count\":1}]}],\"dropped_products\":[{\"product_id\":9402,\"product_name\":\"Synthetic Gadget\",\"product_alias\":\"SG\",\"product_group_id\":9501,\"product_group_name\":\"Synthetic Item Group\",\"main_unit\":\"Pcs\",\"alternative_unit\":\"\",\"product_status\":\"dropped\",\"sale_quantity_main\":0,\"sale_quantity_alternative\":0,\"return_quantity_main\":0,\"return_quantity_alternative\":0,\"net_sale_quantity_main\":0,\"net_sale_quantity_alternative\":0,\"sale_amount\":0,\"return_amount\":0,\"net_sale_amount\":0,\"taxable_amount\":0,\"gst_amount\":0,\"cgst_amount\":0,\"sgst_amount\":0,\"igst_amount\":0,\"sale_invoice_count\":0,\"sale_return_invoice_count\":0,\"last_purchase_rate\":241.35,\"average_rate\":241.35,\"min_rate\":241.35,\"max_rate\":241.35,\"weighted_average_rate\":241.35,\"first_purchase_date\":\"2024-11-14\",\"last_purchase_date\":\"2024-11-14\",\"days_since_last_purchase\":502,\"purchase_frequency_count\":1,\"average_purchase_interval_days\":0,\"daily_trend\":[],\"weekly_trend\":[],\"monthly_trend\":[]}]},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.customers.product-analytics\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"financialYears\":[\"2025\",\"2024\"],\"customerId\":7001,\"fromDate\":\"2025-04-01\",\"toDate\":\"2026-03-31\",\"page\":1,\"pageSize\":100,\"totalRows\":2,\"rowCount\":2,\"hasMore\":false,\"elapsedMs\":26,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"99700517-cb14-5d58-2275-8349456bdf24"},{"name":"busy.day-end.summary – Day-end summary","id":"09de6593-f5de-9248-5a66-61a7b72568ab","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"date\": \"{{financialYear}}-04-01\",\n  \"cashMasterCode\": 1\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/day-end-report-summary","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/day-end-report-summary</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.day-end.summary</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.day-end.summary</code></strong> (BusyNotify <code>POST /v1/day-end-report-summary</code>). The cash position of a day or range: opening cash, then cash, party (every other account) and others (what balances them) for Sales, Purchase, Sales Return (Cr. Note), Purchase Return (Dr. Note), Receipt, Payment, Journal and Contra, then closing cash — always ten rows, not paged. <strong>Read only. Account and balance data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, date | (startDate + endDate), cashMasterCode? }</code>.</p>\n<ul>\n<li>Send <strong>either</strong> <code>date</code> (one day) <strong>or</strong> both <code>startDate</code> and <code>endDate</code> (inclusive); both forms together, or one side alone, is <code>400</code>. Dates are real <code>YYYY-MM-DD</code> dates inside the April–March year.</li>\n<li><code>cashMasterCode</code>: the cash account's code (whole number 1–2147483647), default 1. The reference's <code>reportDate</code>, <code>start_date</code>, <code>cash_master_code</code>, <code>partyRootGroupCode</code> and <code>authToken</code> are refused.</li>\n</ul>\n<p>Response (200): <code>data</code> = the rows <code>{ type, total_amount, cash_signed, party_signed, others_signed, total_amount_display, cash, party, others }</code> (negative = debit; displays <code>… Dr</code> / <code>… Cr</code>, <code>0.00</code>, empty for zero on the opening and closing rows). Opening cash = every opening-balance row of the cash account plus every earlier line; closing = opening + the range's lines.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5m.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","day-end-report-summary"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"5a631e9a-04cd-30ef-1dd7-76ef1ff87d57","name":"200 – synthetic day-end summary (one day)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"date\": \"{{financialYear}}-04-01\",\n  \"cashMasterCode\": 1\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/day-end-report-summary","description":"**Local** · `POST {{baseUrl}}/api/v1/day-end-report-summary` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.day-end.summary`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.day-end.summary`** (BusyNotify `POST /v1/day-end-report-summary`). The cash position of a day or range: opening cash, then cash, party (every other account) and others (what balances them) for Sales, Purchase, Sales Return (Cr. Note), Purchase Return (Dr. Note), Receipt, Payment, Journal and Contra, then closing cash — always ten rows, not paged. **Read only. Account and balance data.**\n\nRequest: `{ companyCode, financialYear, date | (startDate + endDate), cashMasterCode? }`.\n- Send **either** `date` (one day) **or** both `startDate` and `endDate` (inclusive); both forms together, or one side alone, is `400`. Dates are real `YYYY-MM-DD` dates inside the April–March year.\n- `cashMasterCode`: the cash account's code (whole number 1–2147483647), default 1. The reference's `reportDate`, `start_date`, `cash_master_code`, `partyRootGroupCode` and `authToken` are refused.\n\nResponse (200): `data` = the rows `{ type, total_amount, cash_signed, party_signed, others_signed, total_amount_display, cash, party, others }` (negative = debit; displays `… Dr` / `… Cr`, `0.00`, empty for zero on the opening and closing rows). Opening cash = every opening-balance row of the cash account plus every earlier line; closing = opening + the range's lines.\n\nCanonical contract: `docs/LOCAL-API.md` section 5m."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":[{\"type\":\"Opening Balance\",\"total_amount\":null,\"cash_signed\":-1250.5,\"party_signed\":0,\"others_signed\":0,\"total_amount_display\":\"\",\"cash\":\"1250.50 Dr\",\"party\":\"\",\"others\":\"\"},{\"type\":\"Sales\",\"total_amount\":1180,\"cash_signed\":-1180,\"party_signed\":1180,\"others_signed\":0,\"total_amount_display\":\"1180.00\",\"cash\":\"1180.00 Dr\",\"party\":\"1180.00 Cr\",\"others\":\"0.00\"},{\"type\":\"Purchase\",\"total_amount\":0,\"cash_signed\":0,\"party_signed\":0,\"others_signed\":0,\"total_amount_display\":\"0.00\",\"cash\":\"0.00\",\"party\":\"0.00\",\"others\":\"0.00\"},{\"type\":\"Sales Return (Cr. Note)\",\"total_amount\":0,\"cash_signed\":0,\"party_signed\":0,\"others_signed\":0,\"total_amount_display\":\"0.00\",\"cash\":\"0.00\",\"party\":\"0.00\",\"others\":\"0.00\"},{\"type\":\"Purchase Return (Dr. Note)\",\"total_amount\":0,\"cash_signed\":0,\"party_signed\":0,\"others_signed\":0,\"total_amount_display\":\"0.00\",\"cash\":\"0.00\",\"party\":\"0.00\",\"others\":\"0.00\"},{\"type\":\"Receipt\",\"total_amount\":0,\"cash_signed\":0,\"party_signed\":0,\"others_signed\":0,\"total_amount_display\":\"0.00\",\"cash\":\"0.00\",\"party\":\"0.00\",\"others\":\"0.00\"},{\"type\":\"Payment\",\"total_amount\":0,\"cash_signed\":0,\"party_signed\":0,\"others_signed\":0,\"total_amount_display\":\"0.00\",\"cash\":\"0.00\",\"party\":\"0.00\",\"others\":\"0.00\"},{\"type\":\"Journal\",\"total_amount\":0,\"cash_signed\":0,\"party_signed\":0,\"others_signed\":0,\"total_amount_display\":\"0.00\",\"cash\":\"0.00\",\"party\":\"0.00\",\"others\":\"0.00\"},{\"type\":\"Contra\",\"total_amount\":0,\"cash_signed\":0,\"party_signed\":0,\"others_signed\":0,\"total_amount_display\":\"0.00\",\"cash\":\"0.00\",\"party\":\"0.00\",\"others\":\"0.00\"},{\"type\":\"Closing Balance\",\"total_amount\":null,\"cash_signed\":-2430.5,\"party_signed\":0,\"others_signed\":0,\"total_amount_display\":\"\",\"cash\":\"2430.50 Dr\",\"party\":\"\",\"others\":\"\"}],\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.day-end.summary\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"reportType\":\"summary\",\"startDate\":\"2025-06-02\",\"endDate\":\"2025-06-02\",\"cashMasterCode\":1,\"rowCount\":10,\"elapsedMs\":21,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"09de6593-f5de-9248-5a66-61a7b72568ab"},{"name":"busy.day-end.detailed – Day-end report, detailed","id":"e705799c-17e3-f7d8-2e86-fde8defb1ffa","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"startDate\": \"{{financialYear}}-04-01\",\n  \"endDate\": \"{{financialYear}}-04-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/day-end-report-detailed","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/day-end-report-detailed</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.day-end.detailed</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.day-end.detailed</code></strong> (BusyNotify <code>POST /v1/day-end-report-detailed</code>). Every account line of a day or range under its voucher type (Sales, Purchase, Sales Return (Cr. Note), Purchase Return (Dr. Note), Receipt, Payment, Journal, Contra), with the amount in its category column — <strong>cash</strong>, <strong>bank</strong>, <strong>bank OD</strong>, <strong>party</strong> or <strong>others</strong>, from the account's parent group or an existing grandparent (111, 112, 128, 116/117/1303) — between the opening and closing cash, bank and bank-OD balances. <strong>Read only. Account, voucher and balance data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, date | (startDate + endDate) }</code> — the same dates as the summary (either form, never both, never one side alone; real <code>YYYY-MM-DD</code> dates inside the year). <code>cashMasterCode</code> and <code>partyRootGroupCode</code> are not accepted here.</p>\n<p>Response (200): <code>data</code> = every row <code>{ type, date (DD-MM-YYYY), date_raw, voucher_no, particulars, cash_signed, bank_signed, bank_od_signed, party_signed, others_signed, cash, bank, bank_od, party, others }</code>. The type is named on its first line; a type without lines is one zero placeholder (<code>date</code> empty, <code>date_raw</code> null); <code>party_signed</code> / <code>others_signed</code> are null on the opening and closing rows. <strong>One complete answer, not paged</strong> (a page would split a type from its label or the closing balances).</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5m.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","day-end-report-detailed"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"3b925065-64f3-f348-8f6d-0cf60a91e30b","name":"200 – synthetic detailed day-end report (one day)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"startDate\": \"{{financialYear}}-04-01\",\n  \"endDate\": \"{{financialYear}}-04-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/day-end-report-detailed","description":"**Local** · `POST {{baseUrl}}/api/v1/day-end-report-detailed` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.day-end.detailed`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.day-end.detailed`** (BusyNotify `POST /v1/day-end-report-detailed`). Every account line of a day or range under its voucher type (Sales, Purchase, Sales Return (Cr. Note), Purchase Return (Dr. Note), Receipt, Payment, Journal, Contra), with the amount in its category column — **cash**, **bank**, **bank OD**, **party** or **others**, from the account's parent group or an existing grandparent (111, 112, 128, 116/117/1303) — between the opening and closing cash, bank and bank-OD balances. **Read only. Account, voucher and balance data.**\n\nRequest: `{ companyCode, financialYear, date | (startDate + endDate) }` — the same dates as the summary (either form, never both, never one side alone; real `YYYY-MM-DD` dates inside the year). `cashMasterCode` and `partyRootGroupCode` are not accepted here.\n\nResponse (200): `data` = every row `{ type, date (DD-MM-YYYY), date_raw, voucher_no, particulars, cash_signed, bank_signed, bank_od_signed, party_signed, others_signed, cash, bank, bank_od, party, others }`. The type is named on its first line; a type without lines is one zero placeholder (`date` empty, `date_raw` null); `party_signed` / `others_signed` are null on the opening and closing rows. **One complete answer, not paged** (a page would split a type from its label or the closing balances).\n\nCanonical contract: `docs/LOCAL-API.md` section 5m."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":[{\"type\":\"Opening Balance\",\"date\":\"02-06-2025\",\"date_raw\":\"2025-06-02\",\"voucher_no\":\"\",\"particulars\":\"\",\"cash_signed\":-1250.5,\"bank_signed\":300,\"bank_od_signed\":0,\"party_signed\":null,\"others_signed\":null,\"cash\":\"1250.50 Dr\",\"bank\":\"300.00 Cr\",\"bank_od\":\"\",\"party\":\"\",\"others\":\"\"},{\"type\":\"Sales\",\"date\":\"02-06-2025\",\"date_raw\":\"2025-06-02\",\"voucher_no\":\"SYN/S/0001\",\"particulars\":\"Synthetic Customer\",\"cash_signed\":0,\"bank_signed\":0,\"bank_od_signed\":0,\"party_signed\":-1180,\"others_signed\":0,\"cash\":\"0.00\",\"bank\":\"0.00\",\"bank_od\":\"0.00\",\"party\":\"1180.00 Dr\",\"others\":\"0.00\"},{\"type\":\"\",\"date\":\"02-06-2025\",\"date_raw\":\"2025-06-02\",\"voucher_no\":\"SYN/S/0001\",\"particulars\":\"Synthetic Sales\",\"cash_signed\":0,\"bank_signed\":0,\"bank_od_signed\":0,\"party_signed\":0,\"others_signed\":1180,\"cash\":\"0.00\",\"bank\":\"0.00\",\"bank_od\":\"0.00\",\"party\":\"0.00\",\"others\":\"1180.00 Cr\"},{\"type\":\"Purchase\",\"date\":\"\",\"date_raw\":null,\"voucher_no\":\"\",\"particulars\":\"\",\"cash_signed\":0,\"bank_signed\":0,\"bank_od_signed\":0,\"party_signed\":0,\"others_signed\":0,\"cash\":\"0.00\",\"bank\":\"0.00\",\"bank_od\":\"0.00\",\"party\":\"0.00\",\"others\":\"0.00\"},{\"type\":\"Sales Return (Cr. Note)\",\"date\":\"\",\"date_raw\":null,\"voucher_no\":\"\",\"particulars\":\"\",\"cash_signed\":0,\"bank_signed\":0,\"bank_od_signed\":0,\"party_signed\":0,\"others_signed\":0,\"cash\":\"0.00\",\"bank\":\"0.00\",\"bank_od\":\"0.00\",\"party\":\"0.00\",\"others\":\"0.00\"},{\"type\":\"Purchase Return (Dr. Note)\",\"date\":\"\",\"date_raw\":null,\"voucher_no\":\"\",\"particulars\":\"\",\"cash_signed\":0,\"bank_signed\":0,\"bank_od_signed\":0,\"party_signed\":0,\"others_signed\":0,\"cash\":\"0.00\",\"bank\":\"0.00\",\"bank_od\":\"0.00\",\"party\":\"0.00\",\"others\":\"0.00\"},{\"type\":\"Receipt\",\"date\":\"\",\"date_raw\":null,\"voucher_no\":\"\",\"particulars\":\"\",\"cash_signed\":0,\"bank_signed\":0,\"bank_od_signed\":0,\"party_signed\":0,\"others_signed\":0,\"cash\":\"0.00\",\"bank\":\"0.00\",\"bank_od\":\"0.00\",\"party\":\"0.00\",\"others\":\"0.00\"},{\"type\":\"Payment\",\"date\":\"\",\"date_raw\":null,\"voucher_no\":\"\",\"particulars\":\"\",\"cash_signed\":0,\"bank_signed\":0,\"bank_od_signed\":0,\"party_signed\":0,\"others_signed\":0,\"cash\":\"0.00\",\"bank\":\"0.00\",\"bank_od\":\"0.00\",\"party\":\"0.00\",\"others\":\"0.00\"},{\"type\":\"Journal\",\"date\":\"\",\"date_raw\":null,\"voucher_no\":\"\",\"particulars\":\"\",\"cash_signed\":0,\"bank_signed\":0,\"bank_od_signed\":0,\"party_signed\":0,\"others_signed\":0,\"cash\":\"0.00\",\"bank\":\"0.00\",\"bank_od\":\"0.00\",\"party\":\"0.00\",\"others\":\"0.00\"},{\"type\":\"Contra\",\"date\":\"\",\"date_raw\":null,\"voucher_no\":\"\",\"particulars\":\"\",\"cash_signed\":0,\"bank_signed\":0,\"bank_od_signed\":0,\"party_signed\":0,\"others_signed\":0,\"cash\":\"0.00\",\"bank\":\"0.00\",\"bank_od\":\"0.00\",\"party\":\"0.00\",\"others\":\"0.00\"},{\"type\":\"Closing Balance\",\"date\":\"02-06-2025\",\"date_raw\":\"2025-06-02\",\"voucher_no\":\"\",\"particulars\":\"\",\"cash_signed\":-1250.5,\"bank_signed\":300,\"bank_od_signed\":0,\"party_signed\":null,\"others_signed\":null,\"cash\":\"1250.50 Dr\",\"bank\":\"300.00 Cr\",\"bank_od\":\"\",\"party\":\"\",\"others\":\"\"}],\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.day-end.detailed\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"reportType\":\"detailed\",\"startDate\":\"2025-06-02\",\"endDate\":\"2025-06-02\",\"rowCount\":11,\"elapsedMs\":24,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"e705799c-17e3-f7d8-2e86-fde8defb1ffa"},{"name":"busy.accounts.monthly-summary – Account monthly summary","id":"ebb287af-4845-3b92-fe0c-a8cee16a862e","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-monthly-summary","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/account-monthly-summary</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.accounts.monthly-summary</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.accounts.monthly-summary</code></strong> (BusyNotify <code>POST /v1/account-monthly-summary</code>). Every account with a non-zero opening, month or closing value in the whole financial year: opening (from its opening-balance rows), debit and credit for each month April → March, and closing, with totals over every account. <strong>Read only. Account and balance data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, page?, pageSize? }</code> — always the whole April–March year; date members are refused. Pages: default 1 / 100, maximum 500.</p>\n<p>Response (200): <code>data</code> = <code>{ rows, totals }</code>. Row: <code>account_id</code>, <code>account_name</code>, <code>opening_balance</code> (absolute), <code>opening_balance_type</code> (<code>dr</code> / <code>cr</code> / null), <code>opening_balance_display</code> (<code>… Dr</code> / <code>… Cr</code> / empty), <code>april_debit</code> … <code>march_credit</code>, the three closing members, <code>opening_signed</code>, <code>closing_signed</code> (negative = debit). Rows by account name (binary), then code. <code>totals</code> cover <strong>every</strong> account and never depend on the page (<code>… _display</code> is <code>0.00</code> for a zero total). Opening-balance rows are summed before joining, so no account is repeated.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5m.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","account-monthly-summary"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"737f9788-1e6c-832c-c4c5-6de7da1dc803","name":"200 – synthetic monthly summary","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-monthly-summary","description":"**Local** · `POST {{baseUrl}}/api/v1/account-monthly-summary` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.accounts.monthly-summary`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.accounts.monthly-summary`** (BusyNotify `POST /v1/account-monthly-summary`). Every account with a non-zero opening, month or closing value in the whole financial year: opening (from its opening-balance rows), debit and credit for each month April → March, and closing, with totals over every account. **Read only. Account and balance data.**\n\nRequest: `{ companyCode, financialYear, page?, pageSize? }` — always the whole April–March year; date members are refused. Pages: default 1 / 100, maximum 500.\n\nResponse (200): `data` = `{ rows, totals }`. Row: `account_id`, `account_name`, `opening_balance` (absolute), `opening_balance_type` (`dr` / `cr` / null), `opening_balance_display` (`… Dr` / `… Cr` / empty), `april_debit` … `march_credit`, the three closing members, `opening_signed`, `closing_signed` (negative = debit). Rows by account name (binary), then code. `totals` cover **every** account and never depend on the page (`… _display` is `0.00` for a zero total). Opening-balance rows are summed before joining, so no account is repeated.\n\nCanonical contract: `docs/LOCAL-API.md` section 5m."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"rows\":[{\"account_id\":7001,\"account_name\":\"Synthetic Customer\",\"opening_balance\":100,\"opening_balance_type\":\"dr\",\"opening_balance_display\":\"100.00 Dr\",\"april_debit\":50,\"april_credit\":20,\"may_debit\":0,\"may_credit\":0,\"june_debit\":0,\"june_credit\":0,\"july_debit\":0,\"july_credit\":30,\"august_debit\":0,\"august_credit\":0,\"september_debit\":0,\"september_credit\":0,\"october_debit\":0,\"october_credit\":0,\"november_debit\":0,\"november_credit\":0,\"december_debit\":0,\"december_credit\":0,\"january_debit\":0,\"january_credit\":0,\"february_debit\":0,\"february_credit\":10,\"march_debit\":0,\"march_credit\":0,\"closing_balance\":90,\"closing_balance_type\":\"dr\",\"closing_balance_display\":\"90.00 Dr\",\"opening_signed\":-100,\"closing_signed\":-90}],\"totals\":{\"opening_balance_total\":100,\"opening_balance_total_type\":\"dr\",\"opening_balance_total_display\":\"100.00 Dr\",\"april_debit_total\":50,\"april_credit_total\":20,\"may_debit_total\":0,\"may_credit_total\":0,\"june_debit_total\":0,\"june_credit_total\":0,\"july_debit_total\":0,\"july_credit_total\":30,\"august_debit_total\":0,\"august_credit_total\":0,\"september_debit_total\":0,\"september_credit_total\":0,\"october_debit_total\":0,\"october_credit_total\":0,\"november_debit_total\":0,\"november_credit_total\":0,\"december_debit_total\":0,\"december_credit_total\":0,\"january_debit_total\":0,\"january_credit_total\":0,\"february_debit_total\":0,\"february_credit_total\":10,\"march_debit_total\":0,\"march_credit_total\":0,\"closing_balance_total\":90,\"closing_balance_total_type\":\"dr\",\"closing_balance_total_display\":\"90.00 Dr\",\"opening_signed_total\":-100,\"closing_signed_total\":-90}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.accounts.monthly-summary\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"fromDate\":\"2025-04-01\",\"toDate\":\"2026-03-31\",\"page\":1,\"pageSize\":100,\"totalRows\":1,\"rowCount\":1,\"hasMore\":false,\"elapsedMs\":33,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"ebb287af-4845-3b92-fe0c-a8cee16a862e"},{"name":"busy.accounts.consolidated-summary – Account consolidated summary","id":"dee9d61b-b63d-2633-64b5-b00e572180eb","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-06-30\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-consolidated-summary","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/account-consolidated-summary</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.accounts.consolidated-summary</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.accounts.consolidated-summary</code></strong> (BusyNotify <code>POST /v1/account-consolidated-summary</code>). Every account with an opening-balance row and a non-zero opening, debit, credit or closing in a period: parent group, opening (debit or credit side), period debit and credit, closing (debit or credit side), with totals over every account. <strong>Read only. Account and balance data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }</code>.</p>\n<ul>\n<li>Dates: real <code>YYYY-MM-DD</code> inside the April–March year. Neither date = the whole year; <strong>one date alone = that one day</strong> (the reference's rule); both = the inclusive range.</li>\n<li>Pages: default 1 / 100, maximum 500.</li>\n</ul>\n<p>Response (200): <code>data</code> = <code>{ rows, totals }</code>. Row: <code>account_id</code>, <code>account_name</code>, <code>parent_group_id</code>, <code>parent_group_name</code> (the parent's name row in BUSY, else the parent master's name), <code>opening_balance_dr</code>, <code>opening_balance_cr</code>, <code>debit_amount</code>, <code>credit_amount</code>, <code>closing_balance_dr</code>, <code>closing_balance_cr</code>, <code>note_text</code> (always empty), <code>opening_signed</code>, <code>closing_signed</code> (negative = debit). Opening = opening-balance rows + the year's lines before <code>fromDate</code>. Rows by account name (binary), then code. <code>totals</code> (opening DR/CR, debit, credit, closing DR/CR) cover every listed account and never depend on the page.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5m.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","account-consolidated-summary"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"ce469d8a-bde6-071e-3e15-7b9beb8fc897","name":"200 – synthetic consolidated summary","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-06-30\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-consolidated-summary","description":"**Local** · `POST {{baseUrl}}/api/v1/account-consolidated-summary` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.accounts.consolidated-summary`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.accounts.consolidated-summary`** (BusyNotify `POST /v1/account-consolidated-summary`). Every account with an opening-balance row and a non-zero opening, debit, credit or closing in a period: parent group, opening (debit or credit side), period debit and credit, closing (debit or credit side), with totals over every account. **Read only. Account and balance data.**\n\nRequest: `{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }`.\n- Dates: real `YYYY-MM-DD` inside the April–March year. Neither date = the whole year; **one date alone = that one day** (the reference's rule); both = the inclusive range.\n- Pages: default 1 / 100, maximum 500.\n\nResponse (200): `data` = `{ rows, totals }`. Row: `account_id`, `account_name`, `parent_group_id`, `parent_group_name` (the parent's name row in BUSY, else the parent master's name), `opening_balance_dr`, `opening_balance_cr`, `debit_amount`, `credit_amount`, `closing_balance_dr`, `closing_balance_cr`, `note_text` (always empty), `opening_signed`, `closing_signed` (negative = debit). Opening = opening-balance rows + the year's lines before `fromDate`. Rows by account name (binary), then code. `totals` (opening DR/CR, debit, credit, closing DR/CR) cover every listed account and never depend on the page.\n\nCanonical contract: `docs/LOCAL-API.md` section 5m."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"rows\":[{\"account_id\":7001,\"account_name\":\"Synthetic Customer\",\"parent_group_id\":3002,\"parent_group_name\":\"Synthetic Retail Debtors\",\"opening_balance_dr\":130,\"opening_balance_cr\":0,\"debit_amount\":0,\"credit_amount\":0,\"closing_balance_dr\":130,\"closing_balance_cr\":0,\"note_text\":\"\",\"opening_signed\":-130,\"closing_signed\":-130}],\"totals\":{\"opening_balance_dr_total\":130,\"opening_balance_cr_total\":0,\"debit_total\":0,\"credit_total\":0,\"closing_balance_dr_total\":130,\"closing_balance_cr_total\":0}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.accounts.consolidated-summary\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"fromDate\":\"2025-05-01\",\"toDate\":\"2025-06-15\",\"page\":1,\"pageSize\":100,\"totalRows\":1,\"rowCount\":1,\"hasMore\":false,\"elapsedMs\":27,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"dee9d61b-b63d-2633-64b5-b00e572180eb"},{"name":"busy.dashboard.sales-summary – Dashboard sales summary","id":"04851fdf-1b38-a811-d862-73d2ae4838fc","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/dashboard-sales-summary","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/dashboard-sales-summary</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.dashboard.sales-summary</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.dashboard.sales-summary</code></strong> (BusyNotify <code>POST /v1/dashboard-sales-summary</code>). The selected Indian financial year's net sales and invoice counts, zero-filled. <strong>Read only. Sales data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear }</code> only (strict camelCase; <code>authToken</code>, <code>company_id</code> and other reference fields are refused).</p>\n<p>Response (200): <code>data</code> = <code>{ daily, weekly, monthly, quarterly, halfYearly }</code>.</p>\n<ul>\n<li><code>daily</code>: every date 1 April → 31 March (365 or 366 rows): <code>date</code>, <code>invoiceCount</code> (distinct sale vouchers), <code>totalSalesAmount</code> (sales minus the absolute returns, two places).</li>\n<li><code>weekly</code>: 7-day blocks from 1 April (<code>W1</code>–<code>W53</code>, the last shorter) — not calendar weeks.</li>\n<li><code>monthly</code> April → March, <code>quarterly</code> Q1–Q4, <code>halfYearly</code> H1–H2: sums of their days.</li>\n<li>Cancelled vouchers are left out (owner-directed correction).</li>\n</ul>\n<p><code>metadata</code>: <code>apiVersion</code>, <code>operation</code>, <code>requestId</code>, <code>companyCode</code>, <code>financialYear</code>, <code>startDate</code>, <code>endDate</code>, the five row counts, <code>elapsedMs</code>, <code>executedAt</code>. The saved example is shortened to 3 days and 2 weeks; its metadata keeps the full counts.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5n.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","dashboard-sales-summary"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"83abe172-15ec-8dd2-5cff-3dff83dfefad","name":"200 – year summary (synthetic, daily and weekly shortened)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/dashboard-sales-summary","description":"**Local** · `POST {{baseUrl}}/api/v1/dashboard-sales-summary` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.dashboard.sales-summary`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.dashboard.sales-summary`** (BusyNotify `POST /v1/dashboard-sales-summary`). The selected Indian financial year's net sales and invoice counts, zero-filled. **Read only. Sales data.**\n\nRequest: `{ companyCode, financialYear }` only (strict camelCase; `authToken`, `company_id` and other reference fields are refused).\n\nResponse (200): `data` = `{ daily, weekly, monthly, quarterly, halfYearly }`.\n- `daily`: every date 1 April → 31 March (365 or 366 rows): `date`, `invoiceCount` (distinct sale vouchers), `totalSalesAmount` (sales minus the absolute returns, two places).\n- `weekly`: 7-day blocks from 1 April (`W1`–`W53`, the last shorter) — not calendar weeks.\n- `monthly` April → March, `quarterly` Q1–Q4, `halfYearly` H1–H2: sums of their days.\n- Cancelled vouchers are left out (owner-directed correction).\n\n`metadata`: `apiVersion`, `operation`, `requestId`, `companyCode`, `financialYear`, `startDate`, `endDate`, the five row counts, `elapsedMs`, `executedAt`. The saved example is shortened to 3 days and 2 weeks; its metadata keeps the full counts.\n\nCanonical contract: `docs/LOCAL-API.md` section 5n."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"daily\":[{\"date\":\"2025-04-01\",\"invoiceCount\":1,\"totalSalesAmount\":1180},{\"date\":\"2025-04-02\",\"invoiceCount\":1,\"totalSalesAmount\":472.5},{\"date\":\"2025-04-03\",\"invoiceCount\":0,\"totalSalesAmount\":0}],\"weekly\":[{\"weekNumber\":1,\"weekLabel\":\"W1\",\"startDate\":\"2025-04-01\",\"endDate\":\"2025-04-07\",\"invoiceCount\":2,\"totalSalesAmount\":1652.5},{\"weekNumber\":2,\"weekLabel\":\"W2\",\"startDate\":\"2025-04-08\",\"endDate\":\"2025-04-14\",\"invoiceCount\":0,\"totalSalesAmount\":0}],\"monthly\":[{\"monthNumber\":1,\"monthLabel\":\"Apr 2025\",\"startDate\":\"2025-04-01\",\"endDate\":\"2025-04-30\",\"invoiceCount\":2,\"totalSalesAmount\":1652.5},{\"monthNumber\":2,\"monthLabel\":\"May 2025\",\"startDate\":\"2025-05-01\",\"endDate\":\"2025-05-31\",\"invoiceCount\":0,\"totalSalesAmount\":0},{\"monthNumber\":3,\"monthLabel\":\"Jun 2025\",\"startDate\":\"2025-06-01\",\"endDate\":\"2025-06-30\",\"invoiceCount\":0,\"totalSalesAmount\":0},{\"monthNumber\":4,\"monthLabel\":\"Jul 2025\",\"startDate\":\"2025-07-01\",\"endDate\":\"2025-07-31\",\"invoiceCount\":0,\"totalSalesAmount\":0},{\"monthNumber\":5,\"monthLabel\":\"Aug 2025\",\"startDate\":\"2025-08-01\",\"endDate\":\"2025-08-31\",\"invoiceCount\":0,\"totalSalesAmount\":0},{\"monthNumber\":6,\"monthLabel\":\"Sep 2025\",\"startDate\":\"2025-09-01\",\"endDate\":\"2025-09-30\",\"invoiceCount\":0,\"totalSalesAmount\":0},{\"monthNumber\":7,\"monthLabel\":\"Oct 2025\",\"startDate\":\"2025-10-01\",\"endDate\":\"2025-10-31\",\"invoiceCount\":0,\"totalSalesAmount\":0},{\"monthNumber\":8,\"monthLabel\":\"Nov 2025\",\"startDate\":\"2025-11-01\",\"endDate\":\"2025-11-30\",\"invoiceCount\":0,\"totalSalesAmount\":0},{\"monthNumber\":9,\"monthLabel\":\"Dec 2025\",\"startDate\":\"2025-12-01\",\"endDate\":\"2025-12-31\",\"invoiceCount\":0,\"totalSalesAmount\":0},{\"monthNumber\":10,\"monthLabel\":\"Jan 2026\",\"startDate\":\"2026-01-01\",\"endDate\":\"2026-01-31\",\"invoiceCount\":0,\"totalSalesAmount\":0},{\"monthNumber\":11,\"monthLabel\":\"Feb 2026\",\"startDate\":\"2026-02-01\",\"endDate\":\"2026-02-28\",\"invoiceCount\":0,\"totalSalesAmount\":0},{\"monthNumber\":12,\"monthLabel\":\"Mar 2026\",\"startDate\":\"2026-03-01\",\"endDate\":\"2026-03-31\",\"invoiceCount\":0,\"totalSalesAmount\":0}],\"quarterly\":[{\"quarterNumber\":1,\"quarterLabel\":\"Q1\",\"startDate\":\"2025-04-01\",\"endDate\":\"2025-06-30\",\"invoiceCount\":2,\"totalSalesAmount\":1652.5},{\"quarterNumber\":2,\"quarterLabel\":\"Q2\",\"startDate\":\"2025-07-01\",\"endDate\":\"2025-09-30\",\"invoiceCount\":0,\"totalSalesAmount\":0},{\"quarterNumber\":3,\"quarterLabel\":\"Q3\",\"startDate\":\"2025-10-01\",\"endDate\":\"2025-12-31\",\"invoiceCount\":0,\"totalSalesAmount\":0},{\"quarterNumber\":4,\"quarterLabel\":\"Q4\",\"startDate\":\"2026-01-01\",\"endDate\":\"2026-03-31\",\"invoiceCount\":0,\"totalSalesAmount\":0}],\"halfYearly\":[{\"halfYearNumber\":1,\"halfYearLabel\":\"H1\",\"startDate\":\"2025-04-01\",\"endDate\":\"2025-09-30\",\"invoiceCount\":2,\"totalSalesAmount\":1652.5},{\"halfYearNumber\":2,\"halfYearLabel\":\"H2\",\"startDate\":\"2025-10-01\",\"endDate\":\"2026-03-31\",\"invoiceCount\":0,\"totalSalesAmount\":0}]},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.dashboard.sales-summary\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"startDate\":\"2025-04-01\",\"endDate\":\"2026-03-31\",\"dailyRowCount\":365,\"weeklyRowCount\":53,\"monthlyRowCount\":12,\"quarterlyRowCount\":4,\"halfYearlyRowCount\":2,\"elapsedMs\":42,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"04851fdf-1b38-a811-d862-73d2ae4838fc"},{"name":"busy.dashboard.sales-trend – Dashboard sales trend","id":"d4fce8b3-2744-6abf-fa20-58f58fbc4ee7","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"period\": \"yearly\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/dashboard-sales-trend","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/dashboard-sales-trend</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.dashboard.sales-trend</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.dashboard.sales-trend</code></strong> (BusyNotify <code>POST /v1/dashboard-sales-trend</code>). Total sales, sales returns and receipts of today, this week, this month or the financial year. <strong>Read only. Sales data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, period? }</code>. <code>period</code>: <code>daily</code> (the default when absent, as the reference), <code>weekly</code> (Monday–Sunday), <code>monthly</code> (calendar month) or <code>yearly</code> (the selected year). Any other value or case, and the reference's aliases (<code>filter</code>, <code>range</code>, <code>dateFilter</code> …), are refused.</p>\n<p>Periods use the <strong>India calendar day</strong> (Asia/Kolkata). Only the part of the period inside the selected financial year is read — never another year's database: <code>metadata.coverage</code> is <code>full</code> or <code>partial</code> (then <code>coveredStartDate</code>/<code>coveredEndDate</code>); a period wholly outside the year is <code>422 PERIOD_OUTSIDE_FINANCIAL_YEAR</code> (<code>field: period</code>). <code>yearly</code> never depends on today.</p>\n<p>Response (200): <code>data</code> = <code>{ period, startDate, endDate, total_sales_amount, total_sales_return_amount, total_receipt_amount }</code> (absolute amounts, two places; one amount per receipt voucher; cancelled vouchers left out).</p>\n<p><code>metadata</code>: <code>apiVersion</code>, <code>operation</code>, <code>requestId</code>, <code>companyCode</code>, <code>financialYear</code>, <code>period</code>, <code>startDate</code>, <code>endDate</code>, <code>financialYearStartDate</code>, <code>financialYearEndDate</code>, <code>coverage</code>, <code>coveredStartDate</code>, <code>coveredEndDate</code>, <code>calculationDate</code>, <code>timeZone</code>, <code>elapsedMs</code>, <code>executedAt</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5n.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","dashboard-sales-trend"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"582860c5-b9f1-d10e-dcdf-084b5fe5b455","name":"200 – weekly trend (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"period\": \"yearly\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/dashboard-sales-trend","description":"**Local** · `POST {{baseUrl}}/api/v1/dashboard-sales-trend` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.dashboard.sales-trend`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.dashboard.sales-trend`** (BusyNotify `POST /v1/dashboard-sales-trend`). Total sales, sales returns and receipts of today, this week, this month or the financial year. **Read only. Sales data.**\n\nRequest: `{ companyCode, financialYear, period? }`. `period`: `daily` (the default when absent, as the reference), `weekly` (Monday–Sunday), `monthly` (calendar month) or `yearly` (the selected year). Any other value or case, and the reference's aliases (`filter`, `range`, `dateFilter` …), are refused.\n\nPeriods use the **India calendar day** (Asia/Kolkata). Only the part of the period inside the selected financial year is read — never another year's database: `metadata.coverage` is `full` or `partial` (then `coveredStartDate`/`coveredEndDate`); a period wholly outside the year is `422 PERIOD_OUTSIDE_FINANCIAL_YEAR` (`field: period`). `yearly` never depends on today.\n\nResponse (200): `data` = `{ period, startDate, endDate, total_sales_amount, total_sales_return_amount, total_receipt_amount }` (absolute amounts, two places; one amount per receipt voucher; cancelled vouchers left out).\n\n`metadata`: `apiVersion`, `operation`, `requestId`, `companyCode`, `financialYear`, `period`, `startDate`, `endDate`, `financialYearStartDate`, `financialYearEndDate`, `coverage`, `coveredStartDate`, `coveredEndDate`, `calculationDate`, `timeZone`, `elapsedMs`, `executedAt`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5n."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"period\": \"weekly\",\n    \"startDate\": \"2025-06-02\",\n    \"endDate\": \"2025-06-08\",\n    \"total_sales_amount\": 118000,\n    \"total_sales_return_amount\": 2360,\n    \"total_receipt_amount\": 94400.5\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.dashboard.sales-trend\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2025\",\n    \"period\": \"weekly\",\n    \"startDate\": \"2025-06-02\",\n    \"endDate\": \"2025-06-08\",\n    \"financialYearStartDate\": \"2025-04-01\",\n    \"financialYearEndDate\": \"2026-03-31\",\n    \"coverage\": \"full\",\n    \"coveredStartDate\": \"2025-06-02\",\n    \"coveredEndDate\": \"2025-06-08\",\n    \"calculationDate\": \"2025-06-04\",\n    \"timeZone\": \"Asia/Kolkata\",\n    \"elapsedMs\": 16,\n    \"executedAt\": \"2026-09-26T10:00:00+00:00\"\n  }\n}"}],"_postman_id":"d4fce8b3-2744-6abf-fa20-58f58fbc4ee7"},{"name":"busy.credit-line.line-stage-stream – Credit-line stage stream, NDJSON","id":"3f6ba744-400c-7d09-2eeb-4ef1d3e1e9d1","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"Accept","value":"application/x-ndjson"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerIds\": [{{customerId}}],\n  \"groupIds\": [{{customerGroupId}}],\n  \"billByBillMode\": \"standard\",\n  \"gracePeriodSource\": \"project\",\n  \"gracePeriodDays\": 5,\n  \"creditLineType\": \"both\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/credit-line/line-stage-stream","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/credit-line/line-stage-stream</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.credit-line.line-stage-stream</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.credit-line.line-stage-stream</code></strong> (BusyNotify <code>POST /v1/credit-line/line-stage-stream</code>). Each target customer's credit-line stage, streamed. <strong>Read only. Customer, contact and balance data.</strong> The codes in the body are synthetic; use your company's customer and customer-group codes.</p>\n<p>Request: <code>{ companyCode, financialYear, customerIds?, groupIds?, billByBillMode?, billByBillPdfConfig?, customerOptionalFields?, gracePeriodSource?, gracePeriodDays?, gracePeriodOptionalField?, creditLineType?, accountBlockOverdueDays?, accountBlockExceedAmount? }</code>.</p>\n<ul>\n<li>At least one code in <code>customerIds</code> or <code>groupIds</code> (1–2147483647, at most 10 000 each; repeats count once). A group includes all its descendant customer groups. Order: the direct codes, then group members by name and code, each once.</li>\n<li>Every former cloud setting is an explicit option: <code>billByBillMode</code> <code>standard</code> (default) / <code>fifo</code>; <code>billByBillPdfConfig</code> <code>{ creditNote, debitNote, saleReturn, generalVoucher, dueDateCalculation }</code> (default all <code>true</code>); <code>customerOptionalFields</code> <code>OF1</code>–<code>OF10</code>; <code>gracePeriodSource</code> <code>project</code> (default, with <code>gracePeriodDays</code> 0–36 500) or <code>optional_field</code> (with <code>gracePeriodOptionalField</code>, default the first optional field); <code>creditLineType</code> <code>both</code> (default) / <code>credit_days</code> / <code>credit_limit</code>; <code>accountBlockOverdueDays</code> + <code>accountBlockExceedAmount</code>. Conflicts (<code>gracePeriodDays</code> with <code>optional_field</code> …), <code>concurrency</code> and unknown members are refused.</li>\n</ul>\n<p>Response (200): <code>Content-Type: application/x-ndjson; charset=utf-8</code>, one <code>{ success, data, metadata }</code> envelope per line, flushed as written:</p>\n<ol>\n<li><code>data.type: \"meta\"</code> — <code>total</code>, <code>direct_customer_count</code>, <code>group_count</code>; metadata adds the calculation date, time zone and every setting as applied.</li>\n<li>per target <code>data.type: \"row\"</code> (<code>customer_id</code>, <code>result</code> with the reference's members, stage among the eleven) <strong>or</strong> a <code>success: false</code> line with <code>metadata.eventType: \"row_error\"</code>, <code>metadata.customerId</code> and <code>metadata.error</code> (not a customer 404, differing address rows 422); the stream continues.</li>\n<li>after each target <code>data.type: \"progress\"</code> — <code>evaluated</code>, <code>failed</code>, <code>total</code>, <code>percent</code>, <code>by_stage</code>.</li>\n<li><code>data.type: \"done\"</code> — <code>summary: { total, evaluated, failed, by_stage, errors }</code>.\nEvery line's metadata carries <code>requestId</code> and a 0-based <code>sequence</code>. Failures before the stream starts (body, company, year, unknown group, empty groups) are ordinary JSON errors; a failure after it started ends it with one <code>fatal_error</code> line.</li>\n</ol>\n<p>Postman shows the whole body after the stream ends; the test below parses every line.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5n.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","credit-line","line-stage-stream"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"d72b0516-8d95-dce2-bc10-e38b3e42781a","name":"200 – NDJSON stream (synthetic: one row, one row_error)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"Accept","value":"application/x-ndjson"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerIds\": [{{customerId}}],\n  \"groupIds\": [{{customerGroupId}}],\n  \"billByBillMode\": \"standard\",\n  \"gracePeriodSource\": \"project\",\n  \"gracePeriodDays\": 5,\n  \"creditLineType\": \"both\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/credit-line/line-stage-stream","description":"**Local** · `POST {{baseUrl}}/api/v1/credit-line/line-stage-stream` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.credit-line.line-stage-stream`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.credit-line.line-stage-stream`** (BusyNotify `POST /v1/credit-line/line-stage-stream`). Each target customer's credit-line stage, streamed. **Read only. Customer, contact and balance data.** The codes in the body are synthetic; use your company's customer and customer-group codes.\n\nRequest: `{ companyCode, financialYear, customerIds?, groupIds?, billByBillMode?, billByBillPdfConfig?, customerOptionalFields?, gracePeriodSource?, gracePeriodDays?, gracePeriodOptionalField?, creditLineType?, accountBlockOverdueDays?, accountBlockExceedAmount? }`.\n- At least one code in `customerIds` or `groupIds` (1–2147483647, at most 10 000 each; repeats count once). A group includes all its descendant customer groups. Order: the direct codes, then group members by name and code, each once.\n- Every former cloud setting is an explicit option: `billByBillMode` `standard` (default) / `fifo`; `billByBillPdfConfig` `{ creditNote, debitNote, saleReturn, generalVoucher, dueDateCalculation }` (default all `true`); `customerOptionalFields` `OF1`–`OF10`; `gracePeriodSource` `project` (default, with `gracePeriodDays` 0–36 500) or `optional_field` (with `gracePeriodOptionalField`, default the first optional field); `creditLineType` `both` (default) / `credit_days` / `credit_limit`; `accountBlockOverdueDays` + `accountBlockExceedAmount`. Conflicts (`gracePeriodDays` with `optional_field` …), `concurrency` and unknown members are refused.\n\nResponse (200): `Content-Type: application/x-ndjson; charset=utf-8`, one `{ success, data, metadata }` envelope per line, flushed as written:\n1. `data.type: \"meta\"` — `total`, `direct_customer_count`, `group_count`; metadata adds the calculation date, time zone and every setting as applied.\n2. per target `data.type: \"row\"` (`customer_id`, `result` with the reference's members, stage among the eleven) **or** a `success: false` line with `metadata.eventType: \"row_error\"`, `metadata.customerId` and `metadata.error` (not a customer 404, differing address rows 422); the stream continues.\n3. after each target `data.type: \"progress\"` — `evaluated`, `failed`, `total`, `percent`, `by_stage`.\n4. `data.type: \"done\"` — `summary: { total, evaluated, failed, by_stage, errors }`.\nEvery line's metadata carries `requestId` and a 0-based `sequence`. Failures before the stream starts (body, company, year, unknown group, empty groups) are ordinary JSON errors; a failure after it started ends it with one `fatal_error` line.\n\nPostman shows the whole body after the stream ends; the test below parses every line.\n\nCanonical contract: `docs/LOCAL-API.md` section 5n."},"status":"OK","code":200,"_postman_previewlanguage":"text","header":[{"key":"Content-Type","value":"application/x-ndjson; charset=utf-8"},{"key":"Transfer-Encoding","value":"chunked"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"type\":\"meta\",\"total\":2,\"direct_customer_count\":2,\"group_count\":1},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.credit-line.line-stage-stream\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"sequence\":0,\"emittedAt\":\"2026-09-26T10:00:00+00:00\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"calculationDate\":\"2025-06-04\",\"timeZone\":\"Asia/Kolkata\",\"options\":{\"billByBillMode\":\"standard\",\"creditNote\":true,\"debitNote\":true,\"saleReturn\":true,\"generalVoucher\":true,\"dueDateCalculation\":true,\"customerOptionalFields\":[],\"gracePeriodSource\":\"project\",\"gracePeriodDays\":5,\"gracePeriodOptionalField\":null,\"creditLineType\":\"both\",\"accountBlockOverdueDays\":null,\"accountBlockExceedAmount\":null}}}\n{\"success\":true,\"data\":{\"type\":\"row\",\"customer_id\":7001,\"result\":{\"customer_id\":7001,\"customer_name\":\"Synthetic Customer\",\"company_code\":\"COMP0001\",\"bill_by_bill_mode\":\"standard\",\"bill_by_bill_count\":1,\"customer_optional_fields\":{},\"bill_by_bill_details\":[{\"reference_number\":\"SYN/S/0001\",\"transaction_date\":\"15-05-2025\",\"due_date\":\"28-05-2025\",\"transaction_type\":\"Sale\",\"total_reference_amount\":5000,\"pending_amount\":5000,\"days_since_invoice\":20,\"credit_days\":10,\"days_until_due\":-7,\"days_overdue\":7,\"is_due\":true,\"is_oldest\":true}],\"customer_data\":{\"User_Id\":7001,\"Account_Name\":\"Synthetic Customer\",\"Mobile_No\":\"910000000000\",\"WhatsApp_No\":\"910000000000\",\"Account_Group_Name\":\"Synthetic Retail Debtors\",\"Account_Group_Id\":3002,\"Maximum_Credit_Limit\":3000,\"Closing_Balance\":-5000,\"Credit_Limit_Status\":1,\"Credit_Days_Status\":1,\"Credit_Days_For_Sale\":10,\"Oldest_Invoice_Days\":20,\"Oldest_Invoice_Number\":\"SYN/S/0001\",\"Balance_Type\":\"Dr.\",\"Tran2_Record_Count\":4,\"Salesman_Code\":9001,\"Salesman_Name\":\"Synthetic Salesman\",\"Salesman_Mobile\":\"910000000001\",\"Salesman_WhatsApp\":\"910000000001\",\"Optional_Fields\":{}},\"stage\":\"account_block\",\"stage_priority\":3,\"reasons\":[\"Account Block: Customer is 10 days overdue, exceeding grace period of 5 days by 5 days.\",\"Account Balance Limit Exceeded: Balance of ₹5,000 exceeds max credit limit of ₹3,000\"],\"applicable_scenarios\":[\"bills_overdue\",\"balance_limit_exceeded\"],\"reasons_overdue\":[\"Account Block: Customer is 10 days overdue, exceeding grace period of 5 days by 5 days.\"],\"reasons_balance_limit\":[\"Account Balance Limit Exceeded: Balance of ₹5,000 exceeds max credit limit of ₹3,000\"],\"details\":{\"balance\":5000,\"balance_direction\":\"debit\",\"receivable_balance\":5000,\"max_credit_limit\":3000,\"balance_exceeds_limit\":true,\"balance_excess_amount\":2000,\"credit_days_allocated\":10,\"oldest_invoice_days\":20,\"days_overdue\":10,\"days_from_due_date\":7,\"duration_expired_threshold\":15,\"account_block_threshold\":30,\"account_block_base_overdue_days\":null,\"account_block_effective_overdue_days\":null,\"account_block_start_overdue_day\":6,\"grace_period_source\":\"project\",\"grace_period_days\":5,\"grace_period_optional_field\":null,\"grace_period_optional_field_value\":null,\"grace_period_exceeded\":true,\"grace_period_exceeded_by\":5,\"credit_limit_status\":1,\"credit_days_status\":1,\"credit_limit_check_enabled\":true,\"credit_days_check_enabled\":true,\"altered_invoice_days\":7,\"credit_days_display\":\"10 d\",\"credit_limit_display\":\"₹3,000\",\"oldest_invoice_days_display\":\"20 d\",\"altered_invoice_days_display\":\"7 d\",\"days_overdue_display\":\"10 d\",\"balance_excess_display\":\"₹2,000\"}}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.credit-line.line-stage-stream\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"sequence\":1,\"emittedAt\":\"2026-09-26T10:00:00+00:00\"}}\n{\"success\":true,\"data\":{\"type\":\"progress\",\"evaluated\":1,\"failed\":0,\"total\":2,\"percent\":50,\"by_stage\":{\"account_block\":1,\"overdue_and_limit_exceeded\":0,\"bills_overdue\":0,\"due_today\":0,\"due_tomorrow\":0,\"due_in_2_days\":0,\"due_in_3_days\":0,\"due_in_4_days\":0,\"due_in_5_days\":0,\"balance_limit_exceeded\":0,\"good_standing\":0}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.credit-line.line-stage-stream\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"sequence\":2,\"emittedAt\":\"2026-09-26T10:00:00+00:00\"}}\n{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"NOT_FOUND\",\"message\":\"The customer is not a customer in this company and financial year.\"},\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"apiVersion\":\"v1\",\"operation\":\"busy.credit-line.line-stage-stream\",\"sequence\":3,\"eventType\":\"row_error\",\"customerId\":7999,\"emittedAt\":\"2026-09-26T10:00:00+00:00\"}}\n{\"success\":true,\"data\":{\"type\":\"progress\",\"evaluated\":1,\"failed\":1,\"total\":2,\"percent\":100,\"by_stage\":{\"account_block\":1,\"overdue_and_limit_exceeded\":0,\"bills_overdue\":0,\"due_today\":0,\"due_tomorrow\":0,\"due_in_2_days\":0,\"due_in_3_days\":0,\"due_in_4_days\":0,\"due_in_5_days\":0,\"balance_limit_exceeded\":0,\"good_standing\":0}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.credit-line.line-stage-stream\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"sequence\":4,\"emittedAt\":\"2026-09-26T10:00:00+00:00\"}}\n{\"success\":true,\"data\":{\"type\":\"done\",\"summary\":{\"total\":2,\"evaluated\":1,\"failed\":1,\"by_stage\":{\"account_block\":1,\"overdue_and_limit_exceeded\":0,\"bills_overdue\":0,\"due_today\":0,\"due_tomorrow\":0,\"due_in_2_days\":0,\"due_in_3_days\":0,\"due_in_4_days\":0,\"due_in_5_days\":0,\"balance_limit_exceeded\":0,\"good_standing\":0},\"errors\":[{\"customer_id\":7999,\"code\":\"NOT_FOUND\"}]}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.credit-line.line-stage-stream\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"sequence\":5,\"emittedAt\":\"2026-09-26T10:00:00+00:00\",\"elapsedMs\":38}}\n"}],"_postman_id":"3f6ba744-400c-7d09-2eeb-4ef1d3e1e9d1"},{"name":"busy.inventory.daybooks – Inventory daybooks","id":"4d1a2874-0ce0-4f68-7691-3b13b455f90f","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-06-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/inventory-daybooks","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/inventory-daybooks</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>fromDate</code>, <code>toDate</code> · operation <code>busy.inventory.daybooks</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.inventory.daybooks</code></strong> (BusyNotify <code>POST /v1/inventory-daybooks</code>). The item lines of purchases, sale returns, material receipts, stock transfers, sales, purchase returns and material issues in a period, one row per date, voucher and item. <strong>Read only. Inventory data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, fromDate, toDate }</code> — both dates required, <code>YYYY-MM-DD</code>, inside the financial year, <code>fromDate</code> not after <code>toDate</code>. The reference's <code>from_date</code>, <code>startDate</code>, <code>endDate</code> … are refused.</p>\n<p>Response (200): <code>data</code> = rows <code>{ date (dd-mm-yyyy), voucher_type, voucher_number, particular, item, quantity, unit }</code>; quantity = ROUND(ABS(SUM), 3) per date, voucher and item. Ordered by date, voucher type (Purchase Voucher, Sale Return, Material Receipt, Stock Transfer, Sales Invoice, Purchase Return, Material Issue), voucher, item. Cancelled vouchers are left out. No row cap, not paged.</p>\n<p><code>metadata</code>: <code>apiVersion</code>, <code>operation</code>, <code>requestId</code>, <code>companyCode</code>, <code>financialYear</code>, <code>fromDate</code>, <code>toDate</code>, <code>rowCount</code>, <code>elapsedMs</code>, <code>executedAt</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5o.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","inventory-daybooks"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"8658bc39-3bef-816b-0eca-9e3db9935a41","name":"200 – daybook rows (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-06-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/inventory-daybooks","description":"**Local** · `POST {{baseUrl}}/api/v1/inventory-daybooks` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear`, `fromDate`, `toDate` · operation `busy.inventory.daybooks`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.inventory.daybooks`** (BusyNotify `POST /v1/inventory-daybooks`). The item lines of purchases, sale returns, material receipts, stock transfers, sales, purchase returns and material issues in a period, one row per date, voucher and item. **Read only. Inventory data.**\n\nRequest: `{ companyCode, financialYear, fromDate, toDate }` — both dates required, `YYYY-MM-DD`, inside the financial year, `fromDate` not after `toDate`. The reference's `from_date`, `startDate`, `endDate` … are refused.\n\nResponse (200): `data` = rows `{ date (dd-mm-yyyy), voucher_type, voucher_number, particular, item, quantity, unit }`; quantity = ROUND(ABS(SUM), 3) per date, voucher and item. Ordered by date, voucher type (Purchase Voucher, Sale Return, Material Receipt, Stock Transfer, Sales Invoice, Purchase Return, Material Issue), voucher, item. Cancelled vouchers are left out. No row cap, not paged.\n\n`metadata`: `apiVersion`, `operation`, `requestId`, `companyCode`, `financialYear`, `fromDate`, `toDate`, `rowCount`, `elapsedMs`, `executedAt`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5o."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":[{\"date\":\"02-06-2025\",\"voucher_type\":\"Purchase Voucher\",\"voucher_number\":\"SYN/P/0001\",\"particular\":\"Synthetic Supplier\",\"item\":\"Synthetic Widget\",\"quantity\":10,\"unit\":\"Pcs\"},{\"date\":\"02-06-2025\",\"voucher_type\":\"Sales Invoice\",\"voucher_number\":\"SYN/S/0001\",\"particular\":\"Synthetic Customer\",\"item\":\"Synthetic Widget\",\"quantity\":4,\"unit\":\"Pcs\"}],\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.inventory.daybooks\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"fromDate\":\"2025-06-01\",\"toDate\":\"2025-06-30\",\"rowCount\":2,\"elapsedMs\":21,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"4d1a2874-0ce0-4f68-7691-3b13b455f90f"},{"name":"busy.receivables.ageing-analysis – Ageing analysis: receivables","id":"b12e86d1-d66b-96fd-d245-af7013edaa9c","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"startDate\": \"{{financialYear}}-04-01\",\n  \"endDate\": \"{{financialYear}}-06-30\",\n  \"statusDate\": \"{{financialYear}}-06-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/ageing-analysis-receivables","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/ageing-analysis-receivables</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>startDate</code>, <code>endDate</code> · operation <code>busy.receivables.ageing-analysis</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.receivables.ageing-analysis</code></strong> (BusyNotify <code>POST /v1/ageing-analysis-receivables</code>). One customer's bills still pending on the status date, balanced by their own BUSY bill reference, in ageing buckets. <strong>Read only. Customer and amount data.</strong> The customer code in the body is synthetic.</p>\n<p>Request: <code>{ companyCode, financialYear, customerId | accountName, startDate, endDate, statusDate? }</code>.</p>\n<ul>\n<li>Exactly one of <code>customerId</code> (customer code) or <code>accountName</code> (exact name or alias). Both together are refused; an ambiguous name is 422; unknown is 404.</li>\n<li><code>startDate</code>/<code>endDate</code> (bill dates) required; <code>statusDate</code> default <code>endDate</code>; all <code>YYYY-MM-DD</code> inside the financial year.</li>\n</ul>\n<p>Response (200): <code>data</code> = pending bills <code>{ reference_number, transaction_type, transaction_date, transaction_date_raw, due_date, due_date_raw, total_amount, pending_amount, age_0_30_days, age_31_60_days, age_61_90_days, age_91_120_days, age_121_150_days, age_151_plus_days, age_days, ref_code, voucher_code, voucher_type, voucher_series_code, signed_balance }</code>. The pending amount appears in at most one bucket; a bill not yet due (negative <code>age_days</code>) is in none. Cancelled vouchers and rejected entries are left out.</p>\n<p><code>metadata</code>: <code>apiVersion</code>, <code>operation</code>, <code>requestId</code>, <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> (resolved), <code>selectedBy</code>, <code>startDate</code>, <code>endDate</code>, <code>statusDate</code>, <code>rowCount</code>, <code>elapsedMs</code>, <code>executedAt</code> (never the submitted name).</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5o.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","ageing-analysis-receivables"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"57f37e39-7256-6a73-2938-33c579fd763a","name":"200 – pending bills in buckets (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"startDate\": \"{{financialYear}}-04-01\",\n  \"endDate\": \"{{financialYear}}-06-30\",\n  \"statusDate\": \"{{financialYear}}-06-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/ageing-analysis-receivables","description":"**Local** · `POST {{baseUrl}}/api/v1/ageing-analysis-receivables` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear`, `startDate`, `endDate` · operation `busy.receivables.ageing-analysis`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.receivables.ageing-analysis`** (BusyNotify `POST /v1/ageing-analysis-receivables`). One customer's bills still pending on the status date, balanced by their own BUSY bill reference, in ageing buckets. **Read only. Customer and amount data.** The customer code in the body is synthetic.\n\nRequest: `{ companyCode, financialYear, customerId | accountName, startDate, endDate, statusDate? }`.\n- Exactly one of `customerId` (customer code) or `accountName` (exact name or alias). Both together are refused; an ambiguous name is 422; unknown is 404.\n- `startDate`/`endDate` (bill dates) required; `statusDate` default `endDate`; all `YYYY-MM-DD` inside the financial year.\n\nResponse (200): `data` = pending bills `{ reference_number, transaction_type, transaction_date, transaction_date_raw, due_date, due_date_raw, total_amount, pending_amount, age_0_30_days, age_31_60_days, age_61_90_days, age_91_120_days, age_121_150_days, age_151_plus_days, age_days, ref_code, voucher_code, voucher_type, voucher_series_code, signed_balance }`. The pending amount appears in at most one bucket; a bill not yet due (negative `age_days`) is in none. Cancelled vouchers and rejected entries are left out.\n\n`metadata`: `apiVersion`, `operation`, `requestId`, `companyCode`, `financialYear`, `customerId` (resolved), `selectedBy`, `startDate`, `endDate`, `statusDate`, `rowCount`, `elapsedMs`, `executedAt` (never the submitted name).\n\nCanonical contract: `docs/LOCAL-API.md` section 5o."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":[{\"reference_number\":\"SYN/S/0001\",\"transaction_type\":\"Sale\",\"transaction_date\":\"10-04-2025\",\"transaction_date_raw\":\"2025-04-10\",\"due_date\":\"10-05-2025\",\"due_date_raw\":\"2025-05-10\",\"total_amount\":1180,\"pending_amount\":680,\"age_0_30_days\":null,\"age_31_60_days\":680,\"age_61_90_days\":null,\"age_91_120_days\":null,\"age_121_150_days\":null,\"age_151_plus_days\":null,\"age_days\":51,\"ref_code\":501,\"voucher_code\":97572,\"voucher_type\":9,\"voucher_series_code\":11,\"signed_balance\":-680},{\"reference_number\":\"SYN/S/0002\",\"transaction_type\":\"Sale\",\"transaction_date\":\"01-06-2025\",\"transaction_date_raw\":\"2025-06-01\",\"due_date\":\"01-06-2025\",\"due_date_raw\":\"2025-06-01\",\"total_amount\":590,\"pending_amount\":590,\"age_0_30_days\":590,\"age_31_60_days\":null,\"age_61_90_days\":null,\"age_91_120_days\":null,\"age_121_150_days\":null,\"age_151_plus_days\":null,\"age_days\":29,\"ref_code\":502,\"voucher_code\":97573,\"voucher_type\":9,\"voucher_series_code\":11,\"signed_balance\":-590}],\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.receivables.ageing-analysis\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"customerId\":7001,\"selectedBy\":\"customerId\",\"startDate\":\"2025-04-01\",\"endDate\":\"2025-06-30\",\"statusDate\":\"2025-06-30\",\"rowCount\":2,\"elapsedMs\":19,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"b12e86d1-d66b-96fd-d245-af7013edaa9c"},{"name":"busy.inventory.stock-aging – Stock ageing, serial numbers","id":"42d98f4a-6ad1-0e75-3bd4-1e89f4581db2","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"asOnDate\": \"{{financialYear}}-06-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/stock-aging-receivable-issuable","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/stock-aging-receivable-issuable</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.inventory.stock-aging</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.inventory.stock-aging</code></strong> (BusyNotify <code>POST /v1/stock-aging-receivable-issuable</code>). The serial-numbered stock in hand on a date, per product and material centre, with ages and a summary. <strong>Read only. Product and serial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, asOnDate?, productId?, materialCenterId? }</code>. <code>asOnDate</code> defaults to today in India and must lie inside the financial year (a past year needs <code>asOnDate</code>). Unknown product or material centre codes are 404.</p>\n<p>Only serial movements dated on or before <code>asOnDate</code> count (a correction of the reference, which read every movement ever recorded). Cancelled vouchers are left out.</p>\n<p>Response (200): <code>data</code> = <code>{ rows, summary }</code>. Row: product, group, material centre, brands and location, price, self value, the product's and the centre's oldest serial with date and age, <code>fifo_aging_date</code>, <code>total_quantity</code> (serials), <code>average_age_days</code>, <code>latest_transaction_date</code>, and the reference's aliases <code>mc_id</code>, <code>mc_name</code>, <code>price</code>, <code>average_age</code>, <code>newest_date</code>. Summary over every row (not paged): combinations, unique products, unique centres, serial numbers, oldest age, weighted average age (with the reference's aliases).</p>\n<p><code>metadata</code>: <code>apiVersion</code>, <code>operation</code>, <code>requestId</code>, <code>companyCode</code>, <code>financialYear</code>, <code>asOnDate</code>, <code>asOnDateSource</code>, <code>timeZone</code>, <code>productId</code>, <code>materialCenterId</code>, <code>rowCount</code>, <code>transactionCount</code>, <code>elapsedMs</code>, <code>executedAt</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5o.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","stock-aging-receivable-issuable"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"26a4afca-1b92-db67-82df-4e9d5f45aa8f","name":"200 – stock with summary (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"asOnDate\": \"{{financialYear}}-06-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/stock-aging-receivable-issuable","description":"**Local** · `POST {{baseUrl}}/api/v1/stock-aging-receivable-issuable` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.inventory.stock-aging`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.inventory.stock-aging`** (BusyNotify `POST /v1/stock-aging-receivable-issuable`). The serial-numbered stock in hand on a date, per product and material centre, with ages and a summary. **Read only. Product and serial data.**\n\nRequest: `{ companyCode, financialYear, asOnDate?, productId?, materialCenterId? }`. `asOnDate` defaults to today in India and must lie inside the financial year (a past year needs `asOnDate`). Unknown product or material centre codes are 404.\n\nOnly serial movements dated on or before `asOnDate` count (a correction of the reference, which read every movement ever recorded). Cancelled vouchers are left out.\n\nResponse (200): `data` = `{ rows, summary }`. Row: product, group, material centre, brands and location, price, self value, the product's and the centre's oldest serial with date and age, `fifo_aging_date`, `total_quantity` (serials), `average_age_days`, `latest_transaction_date`, and the reference's aliases `mc_id`, `mc_name`, `price`, `average_age`, `newest_date`. Summary over every row (not paged): combinations, unique products, unique centres, serial numbers, oldest age, weighted average age (with the reference's aliases).\n\n`metadata`: `apiVersion`, `operation`, `requestId`, `companyCode`, `financialYear`, `asOnDate`, `asOnDateSource`, `timeZone`, `productId`, `materialCenterId`, `rowCount`, `transactionCount`, `elapsedMs`, `executedAt`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5o."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"rows\":[{\"product_id\":9401,\"product_name\":\"Synthetic Widget\",\"product_group_id\":5001,\"product_group_name\":\"Synthetic Group\",\"material_center_id\":8101,\"material_center_name\":\"Synthetic Store\",\"manufacturing_brand\":\"Synthetic Brand\",\"consumer_brand\":\"\",\"product_location\":\"\",\"product_price\":120.5,\"product_self_value\":90,\"global_oldest_serial_no\":\"SYN-SN-0001\",\"global_oldest_date\":\"2025-04-15\",\"global_oldest_age_days\":76,\"center_oldest_serial_no\":\"SYN-SN-0001\",\"center_oldest_date\":\"2025-04-15\",\"center_oldest_age_days\":76,\"fifo_aging_date\":\"2025-04-15\",\"total_quantity\":2,\"average_age_days\":58.5,\"latest_transaction_date\":\"2025-05-20\",\"mc_id\":8101,\"mc_name\":\"Synthetic Store\",\"price\":120.5,\"average_age\":58.5,\"newest_date\":\"2025-05-20\"}],\"summary\":{\"total_product_material_center_combinations\":1,\"total_item_material_center_combinations\":1,\"total_unique_products\":1,\"total_unique_material_centers\":1,\"total_serial_numbers\":2,\"oldest_stock_age_overall_days\":76,\"oldest_stock_age_overall\":76,\"average_stock_age_days\":58.5,\"average_stock_age\":58.5}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.inventory.stock-aging\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"asOnDate\":\"2025-06-30\",\"asOnDateSource\":\"request\",\"timeZone\":\"Asia/Kolkata\",\"productId\":9401,\"materialCenterId\":null,\"rowCount\":1,\"transactionCount\":2,\"elapsedMs\":24,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"42d98f4a-6ad1-0e75-3bd4-1e89f4581db2"},{"name":"busy.customers.unbilled – Unbilled customers","id":"023cfe75-5f3a-a582-b3cd-017f3a41dea9","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"asOnDate\": \"{{financialYear}}-06-30\",\n  \"billingMode\": \"negative\",\n  \"billingRule\": \"lastBill\",\n  \"billingWindow\": \"7_days\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/unbilled-customers","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/unbilled-customers</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.customers.unbilled</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.customers.unbilled</code></strong> (BusyNotify <code>POST /v1/unbilled-customers</code>). The Sundry Debtors with no sale bill on a date, or selected by their billing in a window, with their last and first bills and receipts and the closing balance on that date. <strong>Read only. Customer and amount data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, asOnDate?, billingMode?, billingRule?, billingWindow?, customDays? }</code>. <code>asOnDate</code> defaults to today in India and must lie inside the financial year. A filter is all three of <code>billingMode</code> (<code>positive</code> / <code>negative</code>), <code>billingRule</code> (<code>lastBill</code> / <code>anyBill</code>) and <code>billingWindow</code> (<code>7_days</code>, <code>30_days</code>, <code>quarter</code>, <code>6_months</code>, <code>custom</code>); <code>customDays</code> (a whole number from 1) only with <code>custom</code>. Partial or conflicting filters are 400 before BUSY is read. The window ends on <code>asOnDate</code>, both ends included; quarter and 6 months are calendar months, clamped to the month's last day.</p>\n<p>Sundry Debtors: parent group or its parent is BUSY's group 116 or named exactly <code>Sundry Debtors</code>. Closing = every Folio1 row + record-type 1 lines from 1 April to <code>asOnDate</code>. One bill or receipt per voucher. Cancelled vouchers are left out.</p>\n<p>Response (200): <code>data</code> = the customers (array, not paged). Amounts are two-decimal texts; dates <code>dd-mm-yyyy</code>; missing history is <code>null</code>.</p>\n<p><code>metadata</code>: <code>apiVersion</code>, <code>operation</code>, <code>requestId</code>, <code>companyCode</code>, <code>financialYear</code>, <code>asOnDate</code>, <code>asOnDateSource</code>, <code>timeZone</code>, <code>financialYearStart</code>, <code>billingMode</code>, <code>billingRule</code>, <code>billingWindow</code>, <code>customDays</code>, <code>windowStartDate</code>, <code>windowEndDate</code>, <code>rowCount</code>, <code>elapsedMs</code>, <code>executedAt</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5p.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","unbilled-customers"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"325b020e-b92d-add0-8892-47a5990135ac","name":"200 – unbilled debtors, negative lastBill 7 days (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"asOnDate\": \"{{financialYear}}-06-30\",\n  \"billingMode\": \"negative\",\n  \"billingRule\": \"lastBill\",\n  \"billingWindow\": \"7_days\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/unbilled-customers","description":"**Local** · `POST {{baseUrl}}/api/v1/unbilled-customers` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.customers.unbilled`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.customers.unbilled`** (BusyNotify `POST /v1/unbilled-customers`). The Sundry Debtors with no sale bill on a date, or selected by their billing in a window, with their last and first bills and receipts and the closing balance on that date. **Read only. Customer and amount data.**\n\nRequest: `{ companyCode, financialYear, asOnDate?, billingMode?, billingRule?, billingWindow?, customDays? }`. `asOnDate` defaults to today in India and must lie inside the financial year. A filter is all three of `billingMode` (`positive` / `negative`), `billingRule` (`lastBill` / `anyBill`) and `billingWindow` (`7_days`, `30_days`, `quarter`, `6_months`, `custom`); `customDays` (a whole number from 1) only with `custom`. Partial or conflicting filters are 400 before BUSY is read. The window ends on `asOnDate`, both ends included; quarter and 6 months are calendar months, clamped to the month's last day.\n\nSundry Debtors: parent group or its parent is BUSY's group 116 or named exactly `Sundry Debtors`. Closing = every Folio1 row + record-type 1 lines from 1 April to `asOnDate`. One bill or receipt per voucher. Cancelled vouchers are left out.\n\nResponse (200): `data` = the customers (array, not paged). Amounts are two-decimal texts; dates `dd-mm-yyyy`; missing history is `null`.\n\n`metadata`: `apiVersion`, `operation`, `requestId`, `companyCode`, `financialYear`, `asOnDate`, `asOnDateSource`, `timeZone`, `financialYearStart`, `billingMode`, `billingRule`, `billingWindow`, `customDays`, `windowStartDate`, `windowEndDate`, `rowCount`, `elapsedMs`, `executedAt`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5p."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":[{\"customer_id\":7001,\"customer_name\":\"Synthetic Customer\",\"parent_group_id\":3002,\"parent_group_name\":\"Synthetic Retail Debtors\",\"root_group_id\":116,\"root_group_name\":\"Sundry Debtors\",\"mobile_number\":\"\",\"last_bill_1_date\":\"12-05-2025\",\"last_bill_1_days\":49,\"last_bill_1_amount\":\"1180.00\",\"last_bill_2_date\":null,\"last_bill_2_days\":null,\"last_bill_2_amount\":null,\"last_bill_3_date\":null,\"last_bill_3_days\":null,\"last_bill_3_amount\":null,\"first_bill_1_date\":\"12-05-2025\",\"first_bill_1_days\":49,\"first_bill_1_amount\":\"1180.00\",\"first_bill_2_date\":null,\"first_bill_2_days\":null,\"first_bill_2_amount\":null,\"last_receipt_1_date\":\"20-06-2025\",\"last_receipt_1_days\":10,\"last_receipt_1_amount\":\"500.00\",\"last_receipt_2_date\":null,\"last_receipt_2_days\":null,\"last_receipt_2_amount\":null,\"last_receipt_3_date\":null,\"last_receipt_3_days\":null,\"last_receipt_3_amount\":null,\"first_receipt_1_date\":\"20-06-2025\",\"first_receipt_1_days\":10,\"first_receipt_1_amount\":\"500.00\",\"first_receipt_2_date\":null,\"first_receipt_2_days\":null,\"first_receipt_2_amount\":null,\"closing_balance\":\"1680.00\",\"closing_balance_type\":\"dr\",\"closing_balance_display\":\"1680.00 Dr\",\"closing_signed\":\"-1680.00\"}],\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.customers.unbilled\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"asOnDate\":\"2025-06-30\",\"asOnDateSource\":\"request\",\"timeZone\":\"Asia/Kolkata\",\"financialYearStart\":\"2025-04-01\",\"billingMode\":\"negative\",\"billingRule\":\"lastBill\",\"billingWindow\":\"7_days\",\"customDays\":null,\"windowStartDate\":\"2025-06-23\",\"windowEndDate\":\"2025-06-30\",\"rowCount\":1,\"elapsedMs\":27,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"023cfe75-5f3a-a582-b3cd-017f3a41dea9"},{"name":"busy.customers.unbilled-profile – Unbilled customer profile","id":"f3dffa67-800c-cf60-fb48-de908f82c3e6","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-06-30\",\n  \"type\": \"standard\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/unbilled-customer-profile","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/unbilled-customer-profile</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.customers.unbilled-profile</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.customers.unbilled-profile</code></strong> (BusyNotify <code>POST /v1/unbilled-customer-profile</code>). One customer's profile, analytics, monthly trends, transactions with running balances, and pending and due bills. <strong>Read only. Customer, contact and amount data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, customerId, additionalFinancialYear?, fromDate?, toDate?, type? }</code>. <code>additionalFinancialYear</code> is a string of comma-separated four-digit years (the customer ledger's contract); every year is checked before any is read, each is read from its own database, and one failed year fails the request (no partial answer). <code>fromDate</code> and <code>toDate</code> (<code>YYYY-MM-DD</code>) come together; without them each year is read whole, with them only its part of the period. The reference date for due days and the balance snapshot is <code>toDate</code>, else today in India. <code>type</code>: <code>standard</code> (default, BUSY's bill references) or <code>FIFO</code>.</p>\n<p><strong>Snapshot year:</strong> the latest requested year starting on or before the reference date gives the profile, credit limit, closing balance and pending/due bills (<code>metadata.snapshotFinancialYear</code>); the order the years are sent in never changes the answer; a reference date before every requested year is 400. Transactions, analytics and trends cover the requested period in every requested year.</p>\n<p>Transactions: record-type 1 lines of the customer, cancelled vouchers left out; an opening-type line is never a transaction; each year's running balance starts at that year's opening (every Folio1 row, <code>opening_balance</code>); the closing is the snapshot year's opening plus its lines up to the reference date. <code>pending_amount</code> is the balance of the voucher's bill references; <code>on_account</code> = a receipt or payment with no bill-reference row. A bill due on or before the reference date is in <code>due_bills</code>, otherwise in <code>pending_bills</code>, never both.</p>\n<p>Response (200): <code>data</code> = <code>{ profile, analytics, trends, transactions, pending_bills, due_bills }</code>; amounts are two-decimal texts.</p>\n<p><code>metadata</code>: <code>apiVersion</code>, <code>operation</code>, <code>requestId</code>, <code>companyCode</code>, <code>financialYear</code>, <code>financialYears</code>, <code>customerId</code>, <code>fromDate</code>, <code>toDate</code>, <code>referenceDate</code>, <code>referenceDateSource</code>, <code>timeZone</code>, <code>pendingBillsType</code>, <code>snapshotFinancialYear</code>, <code>rowCount</code>, <code>pendingBillCount</code>, <code>dueBillCount</code>, <code>elapsedMs</code>, <code>executedAt</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5p.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","unbilled-customer-profile"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"cbc8144c-f15a-e1c9-c60a-026494f6a4ad","name":"200 – profile, transactions and bills (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-06-30\",\n  \"type\": \"standard\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/unbilled-customer-profile","description":"**Local** · `POST {{baseUrl}}/api/v1/unbilled-customer-profile` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear`, `customerId` · operation `busy.customers.unbilled-profile`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.customers.unbilled-profile`** (BusyNotify `POST /v1/unbilled-customer-profile`). One customer's profile, analytics, monthly trends, transactions with running balances, and pending and due bills. **Read only. Customer, contact and amount data.**\n\nRequest: `{ companyCode, financialYear, customerId, additionalFinancialYear?, fromDate?, toDate?, type? }`. `additionalFinancialYear` is a string of comma-separated four-digit years (the customer ledger's contract); every year is checked before any is read, each is read from its own database, and one failed year fails the request (no partial answer). `fromDate` and `toDate` (`YYYY-MM-DD`) come together; without them each year is read whole, with them only its part of the period. The reference date for due days and the balance snapshot is `toDate`, else today in India. `type`: `standard` (default, BUSY's bill references) or `FIFO`.\n\n**Snapshot year:** the latest requested year starting on or before the reference date gives the profile, credit limit, closing balance and pending/due bills (`metadata.snapshotFinancialYear`); the order the years are sent in never changes the answer; a reference date before every requested year is 400. Transactions, analytics and trends cover the requested period in every requested year.\n\nTransactions: record-type 1 lines of the customer, cancelled vouchers left out; an opening-type line is never a transaction; each year's running balance starts at that year's opening (every Folio1 row, `opening_balance`); the closing is the snapshot year's opening plus its lines up to the reference date. `pending_amount` is the balance of the voucher's bill references; `on_account` = a receipt or payment with no bill-reference row. A bill due on or before the reference date is in `due_bills`, otherwise in `pending_bills`, never both.\n\nResponse (200): `data` = `{ profile, analytics, trends, transactions, pending_bills, due_bills }`; amounts are two-decimal texts.\n\n`metadata`: `apiVersion`, `operation`, `requestId`, `companyCode`, `financialYear`, `financialYears`, `customerId`, `fromDate`, `toDate`, `referenceDate`, `referenceDateSource`, `timeZone`, `pendingBillsType`, `snapshotFinancialYear`, `rowCount`, `pendingBillCount`, `dueBillCount`, `elapsedMs`, `executedAt`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5p."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"profile\":{\"customer_id\":7001,\"customer_name\":\"Synthetic Customer\",\"customer_alias\":\"SYN-CUST\",\"customer_print_name\":\"Synthetic Customer Pvt\",\"parent_group_id\":3002,\"parent_group_name\":\"Synthetic Retail Debtors\",\"root_group_id\":116,\"root_group_name\":\"Sundry Debtors\",\"mobile_number\":\"\",\"whatsapp_number\":\"\",\"email_id\":\"\",\"station\":\"Synthetic Town\",\"gst_number\":\"\",\"pan_number\":\"\"},\"analytics\":{\"closing_balance\":\"-1680.00\",\"pending_balance\":\"0.00\",\"due_balance\":\"680.00\",\"credit_limit\":\"5000.00\",\"total_sales_amount\":\"1180.00\",\"total_sale_return_amount\":\"0.00\",\"total_receipts_amount\":\"500.00\",\"total_payments_amount\":\"0.00\",\"total_journal_adjustment_amount\":\"0.00\",\"total_transaction_count\":2,\"sales_count\":1,\"sale_return_count\":0,\"receipt_count\":1,\"payment_count\":0,\"journal_count\":0,\"last_transaction_date\":\"2025-06-20\",\"last_bill_date\":\"2025-05-12\",\"last_receipt_date\":\"2025-06-20\",\"days_since_last_transaction\":10,\"days_since_last_bill\":49,\"days_since_last_receipt\":10,\"average_billing_interval_days\":0,\"average_receipt_interval_days\":0,\"active_month_count\":2,\"first_transaction_date\":\"2025-05-12\"},\"trends\":{\"monthly_sales_amount\":[{\"financial_year\":\"2025\",\"month\":\"2025-05\",\"amount\":\"1180.00\"}],\"monthly_receipt_amount\":[{\"financial_year\":\"2025\",\"month\":\"2025-06\",\"amount\":\"500.00\"}],\"monthly_bill_count\":[{\"financial_year\":\"2025\",\"month\":\"2025-05\",\"count\":1}],\"monthly_collection_count\":[{\"financial_year\":\"2025\",\"month\":\"2025-06\",\"count\":1}]},\"transactions\":[{\"financial_year\":\"2025\",\"transaction_date\":\"12-05-2025\",\"transaction_date_raw\":\"2025-05-12\",\"days_since_transaction\":49,\"voucher_type\":9,\"transaction_type\":\"Sale\",\"voucher_code\":97572,\"voucher_no\":\"SYN/S/0001\",\"reference_number\":\"SYN/S/0001\",\"due_date\":\"11-06-2025\",\"due_date_raw\":\"2025-06-11\",\"days_until_due\":-19,\"days_overdue\":19,\"debit\":\"1180.00\",\"credit\":\"0.00\",\"signed_amount\":\"-1180.00\",\"running_balance\":\"-2180.00\",\"pending_amount\":\"680.00\",\"is_due\":\"YES\",\"on_account\":\"N\",\"voucher_series_code\":11,\"opening_balance\":\"-1000.00\"},{\"financial_year\":\"2025\",\"transaction_date\":\"20-06-2025\",\"transaction_date_raw\":\"2025-06-20\",\"days_since_transaction\":10,\"voucher_type\":14,\"transaction_type\":\"Receipt\",\"voucher_code\":97580,\"voucher_no\":\"SYN/R/0001\",\"reference_number\":\"SYN/R/0001\",\"due_date\":null,\"due_date_raw\":null,\"days_until_due\":null,\"days_overdue\":0,\"debit\":\"0.00\",\"credit\":\"500.00\",\"signed_amount\":\"500.00\",\"running_balance\":\"-1680.00\",\"pending_amount\":\"0.00\",\"is_due\":\"NO\",\"on_account\":\"N\",\"voucher_series_code\":12,\"opening_balance\":\"-1000.00\"}],\"pending_bills\":[],\"due_bills\":[{\"financial_year\":\"2025\",\"transaction_date\":\"12-05-2025\",\"transaction_date_raw\":\"2025-05-12\",\"transaction_type\":\"Sale\",\"reference_number\":\"SYN/S/0001\",\"invoice_number\":\"SYN/S/0001\",\"total_reference_amount\":\"1180.00\",\"total_pending_amount\":\"680.00\",\"is_due\":\"YES\",\"due_date\":\"11-06-2025\",\"due_date_raw\":\"2025-06-11\",\"days_until_due\":-19,\"days_overdue\":19}]},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.customers.unbilled-profile\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"financialYears\":[\"2025\"],\"customerId\":7001,\"fromDate\":\"2025-04-01\",\"toDate\":\"2025-06-30\",\"referenceDate\":\"2025-06-30\",\"referenceDateSource\":\"request\",\"timeZone\":\"Asia/Kolkata\",\"pendingBillsType\":\"standard\",\"snapshotFinancialYear\":\"2025\",\"rowCount\":2,\"pendingBillCount\":0,\"dueBillCount\":1,\"elapsedMs\":42,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"},{"id":"23d719d6-8cc0-a210-d00a-6f5900e3e180","name":"400 – fromDate without toDate (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-06-30\",\n  \"type\": \"standard\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/unbilled-customer-profile","description":"**Local** · `POST {{baseUrl}}/api/v1/unbilled-customer-profile` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear`, `customerId` · operation `busy.customers.unbilled-profile`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.customers.unbilled-profile`** (BusyNotify `POST /v1/unbilled-customer-profile`). One customer's profile, analytics, monthly trends, transactions with running balances, and pending and due bills. **Read only. Customer, contact and amount data.**\n\nRequest: `{ companyCode, financialYear, customerId, additionalFinancialYear?, fromDate?, toDate?, type? }`. `additionalFinancialYear` is a string of comma-separated four-digit years (the customer ledger's contract); every year is checked before any is read, each is read from its own database, and one failed year fails the request (no partial answer). `fromDate` and `toDate` (`YYYY-MM-DD`) come together; without them each year is read whole, with them only its part of the period. The reference date for due days and the balance snapshot is `toDate`, else today in India. `type`: `standard` (default, BUSY's bill references) or `FIFO`.\n\n**Snapshot year:** the latest requested year starting on or before the reference date gives the profile, credit limit, closing balance and pending/due bills (`metadata.snapshotFinancialYear`); the order the years are sent in never changes the answer; a reference date before every requested year is 400. Transactions, analytics and trends cover the requested period in every requested year.\n\nTransactions: record-type 1 lines of the customer, cancelled vouchers left out; an opening-type line is never a transaction; each year's running balance starts at that year's opening (every Folio1 row, `opening_balance`); the closing is the snapshot year's opening plus its lines up to the reference date. `pending_amount` is the balance of the voucher's bill references; `on_account` = a receipt or payment with no bill-reference row. A bill due on or before the reference date is in `due_bills`, otherwise in `pending_bills`, never both.\n\nResponse (200): `data` = `{ profile, analytics, trends, transactions, pending_bills, due_bills }`; amounts are two-decimal texts.\n\n`metadata`: `apiVersion`, `operation`, `requestId`, `companyCode`, `financialYear`, `financialYears`, `customerId`, `fromDate`, `toDate`, `referenceDate`, `referenceDateSource`, `timeZone`, `pendingBillsType`, `snapshotFinancialYear`, `rowCount`, `pendingBillCount`, `dueBillCount`, `elapsedMs`, `executedAt`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5p."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"INVALID_PARAMETER\",\"message\":\"toDate is required when fromDate is sent.\",\"field\":\"toDate\"},\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"apiVersion\":\"v1\"}}"}],"_postman_id":"f3dffa67-800c-cf60-fb48-de908f82c3e6"},{"name":"busy.customers.product-group-discounts – Customer product-group discounts","id":"31bb96c8-012d-c73d-feb6-4d4db40bb4ef","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/customer-product-group-discounts","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/customer-product-group-discounts</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.customers.product-group-discounts</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.customers.product-group-discounts</code></strong> (BusyNotify <code>POST /v1/customer-product-group-discounts</code>). One customer's discount rows per product group, as BUSY stores them. <strong>Read only. Customer and discount data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, customerId? | customerName?, page?, pageSize? }</code> — exactly one selector. <code>customerName</code> matches the customer's name, then alias, then <code>Help1</code> alternate name (spaces trimmed, A–Z case ignored); several customers at the best match are 422, none 404; the name is never echoed (<code>metadata.selectedBy</code>). <code>page</code> from 1, <code>pageSize</code> 1–500 (default 100).</p>\n<p>Rows: every sale discount row (<code>Tran10</code>, voucher type 9, record type 3, no third master) with its product group (a missing group keeps the row with empty names), <code>effective_date</code>, <code>discount_percent</code> (D1), <code>mrp</code> (D2), <code>sale_price</code> (D3), <code>sale_price_du</code> (D4), <code>compound_discount_percent</code> (D5), <code>d6_raw</code>, <code>d8_raw</code>, <code>d9_raw</code> (four places), <code>c1_raw</code>, <code>c2_raw</code>. <code>discount_row_id</code> is the row's position in the customer's whole ordered list (group name, group, date, BUSY line, values): BUSY has no row key.</p>\n<p>Response (200): <code>data</code> = <code>{ rows }</code>. <code>metadata</code>: <code>apiVersion</code>, <code>operation</code>, <code>requestId</code>, <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code>, <code>selectedBy</code>, <code>page</code>, <code>pageSize</code>, <code>totalRows</code>, <code>rowCount</code>, <code>hasMore</code>, <code>elapsedMs</code>, <code>executedAt</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5p.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","customer-product-group-discounts"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"6a29cc2e-cf03-6fa2-3e9d-e77a7e8cda79","name":"200 – two product-group discounts (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/customer-product-group-discounts","description":"**Local** · `POST {{baseUrl}}/api/v1/customer-product-group-discounts` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.customers.product-group-discounts`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.customers.product-group-discounts`** (BusyNotify `POST /v1/customer-product-group-discounts`). One customer's discount rows per product group, as BUSY stores them. **Read only. Customer and discount data.**\n\nRequest: `{ companyCode, financialYear, customerId? | customerName?, page?, pageSize? }` — exactly one selector. `customerName` matches the customer's name, then alias, then `Help1` alternate name (spaces trimmed, A–Z case ignored); several customers at the best match are 422, none 404; the name is never echoed (`metadata.selectedBy`). `page` from 1, `pageSize` 1–500 (default 100).\n\nRows: every sale discount row (`Tran10`, voucher type 9, record type 3, no third master) with its product group (a missing group keeps the row with empty names), `effective_date`, `discount_percent` (D1), `mrp` (D2), `sale_price` (D3), `sale_price_du` (D4), `compound_discount_percent` (D5), `d6_raw`, `d8_raw`, `d9_raw` (four places), `c1_raw`, `c2_raw`. `discount_row_id` is the row's position in the customer's whole ordered list (group name, group, date, BUSY line, values): BUSY has no row key.\n\nResponse (200): `data` = `{ rows }`. `metadata`: `apiVersion`, `operation`, `requestId`, `companyCode`, `financialYear`, `customerId`, `selectedBy`, `page`, `pageSize`, `totalRows`, `rowCount`, `hasMore`, `elapsedMs`, `executedAt`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5p."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"rows\":[{\"discount_row_id\":1,\"customer_id\":7001,\"customer_name\":\"Synthetic Customer\",\"customer_alias\":\"SYN-CUST\",\"product_group_id\":5002,\"product_group_name\":\"Synthetic Gadgets\",\"product_group_alias\":\"\",\"effective_date\":\"2025-04-01\",\"mrp\":0,\"sale_price\":0,\"sale_price_du\":0,\"discount_percent\":7.5,\"compound_discount_percent\":2,\"d6_raw\":0,\"d8_raw\":0,\"d9_raw\":0,\"c1_raw\":\"\",\"c2_raw\":\"\"},{\"discount_row_id\":2,\"customer_id\":7001,\"customer_name\":\"Synthetic Customer\",\"customer_alias\":\"SYN-CUST\",\"product_group_id\":5001,\"product_group_name\":\"Synthetic Widgets\",\"product_group_alias\":\"SYN-WID\",\"effective_date\":\"2025-04-01\",\"mrp\":0,\"sale_price\":0,\"sale_price_du\":0,\"discount_percent\":5,\"compound_discount_percent\":0,\"d6_raw\":0,\"d8_raw\":0,\"d9_raw\":0,\"c1_raw\":\"\",\"c2_raw\":\"\"}]},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.customers.product-group-discounts\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"customerId\":7001,\"selectedBy\":\"customerId\",\"page\":1,\"pageSize\":100,\"totalRows\":2,\"rowCount\":2,\"hasMore\":false,\"elapsedMs\":12,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"},{"id":"3fe46e1c-b63e-7d1b-361d-a9ff026ed916","name":"422 – several customers share that name (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/customer-product-group-discounts","description":"**Local** · `POST {{baseUrl}}/api/v1/customer-product-group-discounts` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.customers.product-group-discounts`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.customers.product-group-discounts`** (BusyNotify `POST /v1/customer-product-group-discounts`). One customer's discount rows per product group, as BUSY stores them. **Read only. Customer and discount data.**\n\nRequest: `{ companyCode, financialYear, customerId? | customerName?, page?, pageSize? }` — exactly one selector. `customerName` matches the customer's name, then alias, then `Help1` alternate name (spaces trimmed, A–Z case ignored); several customers at the best match are 422, none 404; the name is never echoed (`metadata.selectedBy`). `page` from 1, `pageSize` 1–500 (default 100).\n\nRows: every sale discount row (`Tran10`, voucher type 9, record type 3, no third master) with its product group (a missing group keeps the row with empty names), `effective_date`, `discount_percent` (D1), `mrp` (D2), `sale_price` (D3), `sale_price_du` (D4), `compound_discount_percent` (D5), `d6_raw`, `d8_raw`, `d9_raw` (four places), `c1_raw`, `c2_raw`. `discount_row_id` is the row's position in the customer's whole ordered list (group name, group, date, BUSY line, values): BUSY has no row key.\n\nResponse (200): `data` = `{ rows }`. `metadata`: `apiVersion`, `operation`, `requestId`, `companyCode`, `financialYear`, `customerId`, `selectedBy`, `page`, `pageSize`, `totalRows`, `rowCount`, `hasMore`, `elapsedMs`, `executedAt`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5p."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"BUSY_DATA_INCONSISTENT\",\"message\":\"More than one customer in BUSY matches that customerName; send customerId instead.\",\"field\":\"customerName\"},\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"apiVersion\":\"v1\"}}"}],"_postman_id":"31bb96c8-012d-c73d-feb6-4d4db40bb4ef"}],"id":"c8fa7173-4769-4801-a3ae-619ca9ba324b","description":"<p>Customer and supplier accounting, ledgers, analyses, day-end and account summaries, dashboards, the credit-line stage stream (NDJSON), inventory and ageing, unbilled customers and discounts. Read only. These are POST requests only because they carry a JSON body; none of them changes BUSY or AI Zeny.</p>\n","_postman_id":"c8fa7173-4769-4801-a3ae-619ca9ba324b","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Registers, Orders & Invoices (read only)","item":[{"name":"busy.purchases.products – Purchase register products","id":"7c99c02a-9615-7c66-d0b8-75dbbea710f6","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-register-products","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/purchase-register-products</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.purchases.products</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.purchases.products</code></strong> (BusyNotify <code>POST /v1/purchase-register-products</code>). Purchase and purchase-return product lines. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, fromDate?, toDate?, supplierId?, productId?, voucherId?, materialCenterId?, includeReturns?, includeCancelled?, page?, pageSize? }</code> — leave optional members out rather than sending them empty. Dates <code>YYYY-MM-DD</code> inside the financial year (default 1 April – 31 March); codes JSON integers 1–2147483647; <code>includeReturns</code> default <code>true</code>, <code>includeCancelled</code> default <code>false</code> (cancelled = Boolean true, 1, -1, true/yes/y); <code>page</code> from 1, <code>pageSize</code> 1–500 (default 100).</p>\n<p>Purchases are positive; purchase returns negative once (quantity, subtotal, total, taxable, GST amount). GST is the item-wise rows of the same voucher, voucher type, item and item line, summed once; no GST evidence is <code>null</code>.</p>\n<p>Response (200): <code>data</code> = <code>[{ voucher_code, voucher_type_id, voucher_date, voucher_number, supplier_id, supplier_name, purchase_type_id, purchase_type_name, line_row_id, line_number, product_id, product_name, product_group_id, product_group_name, material_center_id, material_center_name, unit_id, unit_name, quantity, unit_price, line_subtotal, line_total, taxable_amount, gst_percent, gst_amount, line_description }]</code>. <code>metadata</code>: the applied filters, <code>page, pageSize, totalRows, rowCount, hasMore</code>, timing.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5i.</p>\n<p><strong>Line descriptions (owner acceptance 2026-10-19):</strong> every line also carries <code>line_description</code> (last member): the voucher line's own description in BUSY (positions 1..n, an empty position as <code>\"\"</code>, <code>[]</code> when the line has none), joined by voucher code and line number. Public guide: <code>docs/public/api/line-descriptions.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","purchase-register-products"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"7c99c02a-9615-7c66-d0b8-75dbbea710f6"},{"name":"busy.purchases.orders.pending – Pending purchase orders","id":"169ab086-97cd-916f-b4b1-fed5b15a43ae","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"status\": \"open\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/pending-purchase-orders","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/pending-purchase-orders</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.purchases.orders.pending</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.purchases.orders.pending</code></strong> (BusyNotify <code>POST /v1/pending-purchase-orders</code>). Purchase orders with their exact reference-code quantity lifecycle. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, fromDate?, toDate?, asOfDate?, supplierId?, productId?, referenceNumber?, status?, includeCancelled?, page?, pageSize? }</code> — leave optional members out rather than sending them empty.</p>\n<ul>\n<li><code>asOfDate</code>: lifecycle up to this date (<code>YYYY-MM-DD</code> inside the year); default today (UTC) within the year.</li>\n<li><code>fromDate</code>/<code>toDate</code>: filter the order date only when sent (not after <code>asOfDate</code>); without them carried-forward orders (BUSY type 1, code -1300) stay.</li>\n<li><code>referenceNumber</code>: the shown order number or the exact reference code, trimmed, at most 200; never echoed.</li>\n<li><code>status</code>: <code>open</code> (default), <code>closed</code>, <code>over_linked</code>, <code>all</code>.</li>\n</ul>\n<p>Every <code>Tran3</code> row of the same <code>RefCode</code> counts (no FIFO, no number guessing); a row of another known supplier never counts; cancelled entries only with <code>includeCancelled: true</code>.</p>\n<p>Response (200): <code>data</code> = <code>[{ purchase_order_refcode, purchase_order_voucher_code, order_row_id, line_number, order_number, order_date, due_date, supplier_id, supplier_name, supplier_source (reference|header), product_id, product_name, product_group_id, material_center_id, material_center_name, ordered_quantity, linked_purchase_quantity, linked_purchase_bill_count, reference_balance_quantity, pending_quantity, over_linked_quantity, status }]</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5i.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","pending-purchase-orders"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"169ab086-97cd-916f-b4b1-fed5b15a43ae"},{"name":"busy.sales.returns.products – Sales return products","id":"8d496ee5-b98c-f20b-8a7b-842faab4dbb6","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-products","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/sales-return-products</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.sales.returns.products</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.sales.returns.products</code></strong> (BusyNotify <code>POST /v1/sales-return-products</code>). Sales-return product lines. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, fromDate?, toDate?, customerId?, productId?, voucherId?, includeCancelled?, page?, pageSize? }</code> — leave optional members out rather than sending them empty. Dates <code>YYYY-MM-DD</code> inside the year; codes JSON integers 1–2147483647; <code>includeCancelled</code> default <code>false</code>; <code>page</code> from 1, <code>pageSize</code> 1–500 (default 100).</p>\n<p>Quantity, subtotal, total, taxable and GST amounts are negative once; unit price and GST percentage unsigned; missing GST evidence is <code>null</code>.</p>\n<p>Response (200): <code>data</code> = <code>[{ voucher_code, voucher_date, voucher_number, customer_id, customer_name, sale_type_id, sale_type_name, line_row_id, line_number, product_id, product_name, product_group_id, product_group_name, material_center_id, material_center_name, unit_id, unit_name, return_quantity, unit_price, return_subtotal, return_total, taxable_amount, gst_percent, gst_amount, line_description }]</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5i.</p>\n<p><strong>Line descriptions (owner acceptance 2026-10-19):</strong> every line also carries <code>line_description</code> (last member): the voucher line's own description in BUSY (positions 1..n, an empty position as <code>\"\"</code>, <code>[]</code> when the line has none), joined by voucher code and line number. Public guide: <code>docs/public/api/line-descriptions.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","sales-return-products"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"8d496ee5-b98c-f20b-8a7b-842faab4dbb6"},{"name":"busy.customers.sales-register – Customer sales register","id":"766b7aff-f4cd-b188-493b-ca983c5864a4","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/customer-sales-register","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/customer-sales-register</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.customers.sales-register</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.customers.sales-register</code></strong> (BusyNotify <code>POST /v1/customer-sales-register</code>). One customer's sale and sales-return vouchers with a summary. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, customerId, fromDate?, toDate?, includeReturns?, includeCancelled?, page?, pageSize? }</code> — <code>customerId</code> required (JSON integer 1–2147483647); leave optional members out rather than sending them empty. <code>includeReturns</code> default <code>true</code>, <code>includeCancelled</code> default <code>false</code>; <code>page</code> from 1, <code>pageSize</code> 1–500 (default 100).</p>\n<p>Sales are positive, returns negative once; <code>taxable_amount</code> / <code>gst_amount</code> from the voucher's item-wise GST rows (null without any). An unknown customer returns no rows and a zero summary.</p>\n<p>Response (200): <code>data</code> = <code>{ rows: [{ voucher_code, voucher_type_id, transaction_type (sale|sales_return), voucher_date, voucher_number, customer_id, customer_name, sale_type_id, sale_type_name, material_center_id, material_center_name, total_amount, sale_amount, taxable_amount, gst_amount }], summary: { voucher_count, sales_total, returns_total, net_total, net_gst_amount } }</code> — the summary covers the whole period, never one page.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5i.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","customer-sales-register"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"766b7aff-f4cd-b188-493b-ca983c5864a4"},{"name":"busy.registers.sales – Sales register","id":"14b824c3-158c-17e7-0aec-6072fd0730d3","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-register","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/sales-register</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.registers.sales</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.registers.sales</code></strong> (BusyNotify <code>POST /v1/sales-register</code>). Sale (type 9) and sales-return (type 3) vouchers: returns negated once, voucher GST (IGST where <code>TaxRate1</code> is 0, else CGST/SGST), other charges, the amount received against each bill and its status. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }</code> — dates <code>YYYY-MM-DD</code> inside the April–March year; <strong>neither date = the whole year, one date alone = that one day</strong> (the reference's rule); <code>fromDate</code> after <code>toDate</code> is refused. <code>page</code> from 1, <code>pageSize</code> 1–500 (default 100). Leave optional members out rather than sending them empty.</p>\n<p><code>receipt_amount</code>: the exact allocations (<code>Tran3</code> method 2) against the voucher's own bill reference codes and party — no FIFO. <code>status</code>: <code>Cancelled</code>, else <code>Pending</code> when the voucher made a bill reference, else <code>N/A</code>. <strong>Cancelled vouchers stay in the rows and the summary</strong>, as the reference. An account with several differing address rows is <code>422 BUSY_DATA_INCONSISTENT</code>.</p>\n<p>Response (200): <code>data</code> = <code>{ rows: [{ date (DD-MM-YYYY), voucher_code, voucher_type_id, voucher_number, customer_id, customer_name, gst_number, mobile_number, sale_type_id, sale_type_name, total_amount, sale_amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, other_amount, material_center_id, material_center_name, receipt_amount, status }], summary: { total_amount_total, sale_amount_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total, other_amount_total, receipt_amount_total, total_tax_amount_total } }</code> — the summary covers the whole range, never one page.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5j.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","sales-register"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"105ad5f3-e2a3-0a73-c98d-8f381f4b6b34","name":"200 – synthetic sale and return","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-register","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-register` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.registers.sales`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.registers.sales`** (BusyNotify `POST /v1/sales-register`). Sale (type 9) and sales-return (type 3) vouchers: returns negated once, voucher GST (IGST where `TaxRate1` is 0, else CGST/SGST), other charges, the amount received against each bill and its status. **Read only. Financial data.**\n\nRequest: `{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }` — dates `YYYY-MM-DD` inside the April–March year; **neither date = the whole year, one date alone = that one day** (the reference's rule); `fromDate` after `toDate` is refused. `page` from 1, `pageSize` 1–500 (default 100). Leave optional members out rather than sending them empty.\n\n`receipt_amount`: the exact allocations (`Tran3` method 2) against the voucher's own bill reference codes and party — no FIFO. `status`: `Cancelled`, else `Pending` when the voucher made a bill reference, else `N/A`. **Cancelled vouchers stay in the rows and the summary**, as the reference. An account with several differing address rows is `422 BUSY_DATA_INCONSISTENT`.\n\nResponse (200): `data` = `{ rows: [{ date (DD-MM-YYYY), voucher_code, voucher_type_id, voucher_number, customer_id, customer_name, gst_number, mobile_number, sale_type_id, sale_type_name, total_amount, sale_amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, other_amount, material_center_id, material_center_name, receipt_amount, status }], summary: { total_amount_total, sale_amount_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total, other_amount_total, receipt_amount_total, total_tax_amount_total } }` — the summary covers the whole range, never one page.\n\nCanonical contract: `docs/LOCAL-API.md` section 5j."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"rows\":[{\"date\":\"02-06-2025\",\"voucher_code\":97561,\"voucher_type_id\":9,\"voucher_number\":\"SYN/S/0001\",\"customer_id\":7001,\"customer_name\":\"Synthetic Customer\",\"gst_number\":\"SYNTHETICGST0\",\"mobile_number\":\"910000000000\",\"sale_type_id\":9311,\"sale_type_name\":\"Synthetic Sale Type\",\"total_amount\":1186.3,\"sale_amount\":1005.34,\"taxable_amount\":1005.34,\"igst_amount\":0,\"cgst_amount\":90.48,\"sgst_amount\":90.48,\"other_amount\":0,\"material_center_id\":9601,\"material_center_name\":\"Synthetic Store\",\"receipt_amount\":500.2,\"status\":\"Pending\"},{\"date\":\"03-06-2025\",\"voucher_code\":97562,\"voucher_type_id\":3,\"voucher_number\":\"SYN/SR/0001\",\"customer_id\":7001,\"customer_name\":\"Synthetic Customer\",\"gst_number\":\"SYNTHETICGST0\",\"mobile_number\":\"910000000000\",\"sale_type_id\":9311,\"sale_type_name\":\"Synthetic Sale Type\",\"total_amount\":-236.09,\"sale_amount\":-200.07,\"taxable_amount\":-200.07,\"igst_amount\":0,\"cgst_amount\":-18.01,\"sgst_amount\":-18.01,\"other_amount\":0,\"material_center_id\":9601,\"material_center_name\":\"Synthetic Store\",\"receipt_amount\":0,\"status\":\"N/A\"}],\"summary\":{\"total_amount_total\":950.21,\"sale_amount_total\":805.27,\"taxable_amount_total\":805.27,\"igst_amount_total\":0,\"cgst_amount_total\":72.47,\"sgst_amount_total\":72.47,\"other_amount_total\":0,\"receipt_amount_total\":500.2,\"total_tax_amount_total\":144.94}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.registers.sales\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"fromDate\":\"2025-06-01\",\"toDate\":\"2025-06-30\",\"page\":1,\"pageSize\":100,\"totalRows\":2,\"rowCount\":2,\"hasMore\":false,\"elapsedMs\":14,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"14b824c3-158c-17e7-0aec-6072fd0730d3"},{"name":"busy.registers.purchase – Purchase register","id":"bee1a9ea-a5d9-1818-a13c-6f7732637a09","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-register","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/purchase-register</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.registers.purchase</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.registers.purchase</code></strong> (BusyNotify <code>POST /v1/purchase-register</code>). Purchase (type 2) and purchase-return (type 10) vouchers: returns negated once, voucher GST, other charges, the amount paid against each bill and its status. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }</code> — dates <code>YYYY-MM-DD</code> inside the April–March year; <strong>neither date = the whole year, one date alone = that one day</strong>; <code>fromDate</code> after <code>toDate</code> is refused. <code>page</code> from 1, <code>pageSize</code> 1–500 (default 100).</p>\n<p><code>payment_amount</code>: the exact allocations against the voucher's own bill reference codes and <strong>its own supplier only</strong> — never another supplier's payment, no FIFO. <code>status</code> Cancelled / Pending / N/A; cancelled vouchers stay in rows and summary, as the reference.</p>\n<p>Response (200): <code>data</code> = <code>{ rows: [{ date, voucher_code, voucher_type_id, voucher_number, account_id, account_name, gst_number, mobile_number, purchase_type_id, purchase_type_name, total_amount, purchase_amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, other_amount, material_center_id, material_center_name, payment_amount, status }], summary: { total_amount_total, purchase_amount_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total, other_amount_total, payment_amount_total, total_tax_amount_total } }</code> — the summary covers the whole range.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5j.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","purchase-register"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"8c81a406-04d7-c860-0a07-8965afc0fe66","name":"200 – synthetic purchase","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-register","description":"**Local** · `POST {{baseUrl}}/api/v1/purchase-register` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.registers.purchase`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.registers.purchase`** (BusyNotify `POST /v1/purchase-register`). Purchase (type 2) and purchase-return (type 10) vouchers: returns negated once, voucher GST, other charges, the amount paid against each bill and its status. **Read only. Financial data.**\n\nRequest: `{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }` — dates `YYYY-MM-DD` inside the April–March year; **neither date = the whole year, one date alone = that one day**; `fromDate` after `toDate` is refused. `page` from 1, `pageSize` 1–500 (default 100).\n\n`payment_amount`: the exact allocations against the voucher's own bill reference codes and **its own supplier only** — never another supplier's payment, no FIFO. `status` Cancelled / Pending / N/A; cancelled vouchers stay in rows and summary, as the reference.\n\nResponse (200): `data` = `{ rows: [{ date, voucher_code, voucher_type_id, voucher_number, account_id, account_name, gst_number, mobile_number, purchase_type_id, purchase_type_name, total_amount, purchase_amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, other_amount, material_center_id, material_center_name, payment_amount, status }], summary: { total_amount_total, purchase_amount_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total, other_amount_total, payment_amount_total, total_tax_amount_total } }` — the summary covers the whole range.\n\nCanonical contract: `docs/LOCAL-API.md` section 5j."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"rows\":[{\"date\":\"05-06-2025\",\"voucher_code\":97571,\"voucher_type_id\":2,\"voucher_number\":\"SYN/P/0001\",\"account_id\":9101,\"account_name\":\"Synthetic Supplier\",\"gst_number\":\"SYNTHETICGST1\",\"mobile_number\":\"910000000001\",\"purchase_type_id\":9312,\"purchase_type_name\":\"Synthetic Purchase Type\",\"total_amount\":2365.31,\"purchase_amount\":2004.5,\"taxable_amount\":2004.5,\"igst_amount\":360.81,\"cgst_amount\":0,\"sgst_amount\":0,\"other_amount\":0,\"material_center_id\":9601,\"material_center_name\":\"Synthetic Store\",\"payment_amount\":1003.1,\"status\":\"Pending\"}],\"summary\":{\"total_amount_total\":2365.31,\"purchase_amount_total\":2004.5,\"taxable_amount_total\":2004.5,\"igst_amount_total\":360.81,\"cgst_amount_total\":0,\"sgst_amount_total\":0,\"other_amount_total\":0,\"payment_amount_total\":1003.1,\"total_tax_amount_total\":360.81}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.registers.purchase\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"fromDate\":\"2025-06-01\",\"toDate\":\"2025-06-30\",\"page\":1,\"pageSize\":100,\"totalRows\":1,\"rowCount\":1,\"hasMore\":false,\"elapsedMs\":14,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"bee1a9ea-a5d9-1818-a13c-6f7732637a09"},{"name":"busy.registers.sales-return – Sales return / credit note register","id":"a36520a9-f47d-80cb-f635-260da63fac7e","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-crnote-register","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/sales-return-crnote-register</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.registers.sales-return</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.registers.sales-return</code></strong> (BusyNotify <code>POST /v1/sales-return-crnote-register</code>). Sales-return vouchers (type 3, as the reference reads) at <strong>voucher level</strong> (not the product lines of <code>busy.sales.returns.products</code>), amounts <strong>as stored</strong> (positive; no double negation), voucher GST, other charges and status. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }</code> — one date alone is that one day; neither date is the whole year.</p>\n<p>Response (200): the sales register's row and summary shape (<code>customer_*</code>, <code>sale_*</code>, <code>receipt_amount</code>, <code>status</code>); the summary covers the whole range. Cancelled vouchers stay, as the reference.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5j.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","sales-return-crnote-register"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"729a08b8-96bb-40c0-be1d-80250f0cfe95","name":"200 – synthetic sales return","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-crnote-register","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-return-crnote-register` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.registers.sales-return`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.registers.sales-return`** (BusyNotify `POST /v1/sales-return-crnote-register`). Sales-return vouchers (type 3, as the reference reads) at **voucher level** (not the product lines of `busy.sales.returns.products`), amounts **as stored** (positive; no double negation), voucher GST, other charges and status. **Read only. Financial data.**\n\nRequest: `{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }` — one date alone is that one day; neither date is the whole year.\n\nResponse (200): the sales register's row and summary shape (`customer_*`, `sale_*`, `receipt_amount`, `status`); the summary covers the whole range. Cancelled vouchers stay, as the reference.\n\nCanonical contract: `docs/LOCAL-API.md` section 5j."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"rows\":[{\"date\":\"03-06-2025\",\"voucher_code\":97562,\"voucher_type_id\":3,\"voucher_number\":\"SYN/SR/0001\",\"customer_id\":7001,\"customer_name\":\"Synthetic Customer\",\"gst_number\":\"SYNTHETICGST0\",\"mobile_number\":\"910000000000\",\"sale_type_id\":9311,\"sale_type_name\":\"Synthetic Sale Type\",\"total_amount\":236.09,\"sale_amount\":200.07,\"taxable_amount\":200.07,\"igst_amount\":0,\"cgst_amount\":18.01,\"sgst_amount\":18.01,\"other_amount\":0,\"material_center_id\":9601,\"material_center_name\":\"Synthetic Store\",\"receipt_amount\":0,\"status\":\"N/A\"}],\"summary\":{\"total_amount_total\":236.09,\"sale_amount_total\":200.07,\"taxable_amount_total\":200.07,\"igst_amount_total\":0,\"cgst_amount_total\":18.01,\"sgst_amount_total\":18.01,\"other_amount_total\":0,\"receipt_amount_total\":0,\"total_tax_amount_total\":36.02}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.registers.sales-return\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"fromDate\":\"2025-06-01\",\"toDate\":\"2025-06-30\",\"page\":1,\"pageSize\":100,\"totalRows\":1,\"rowCount\":1,\"hasMore\":false,\"elapsedMs\":14,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"a36520a9-f47d-80cb-f635-260da63fac7e"},{"name":"busy.registers.purchase-return – Purchase return / debit note register","id":"5b06d140-ac92-219e-b83e-350a5c9ad4fe","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-return-drnote-register","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/purchase-return-drnote-register</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.registers.purchase-return</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.registers.purchase-return</code></strong> (BusyNotify <code>POST /v1/purchase-return-drnote-register</code>). Purchase-return vouchers (type 10, as the reference reads) at voucher level, amounts <strong>as stored</strong> (positive), voucher GST, other charges and status. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }</code> — one date alone is that one day; neither date is the whole year.</p>\n<p>Response (200): the purchase register's row and summary shape (<code>account_*</code>, <code>purchase_*</code>, <code>payment_amount</code>, <code>status</code>); the summary covers the whole range. Cancelled vouchers stay, as the reference.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5j.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","purchase-return-drnote-register"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"a629ebf3-c3c3-c930-07e6-cf79072e9799","name":"200 – synthetic purchase return","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-return-drnote-register","description":"**Local** · `POST {{baseUrl}}/api/v1/purchase-return-drnote-register` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.registers.purchase-return`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.registers.purchase-return`** (BusyNotify `POST /v1/purchase-return-drnote-register`). Purchase-return vouchers (type 10, as the reference reads) at voucher level, amounts **as stored** (positive), voucher GST, other charges and status. **Read only. Financial data.**\n\nRequest: `{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }` — one date alone is that one day; neither date is the whole year.\n\nResponse (200): the purchase register's row and summary shape (`account_*`, `purchase_*`, `payment_amount`, `status`); the summary covers the whole range. Cancelled vouchers stay, as the reference.\n\nCanonical contract: `docs/LOCAL-API.md` section 5j."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"rows\":[{\"date\":\"07-06-2025\",\"voucher_code\":97572,\"voucher_type_id\":10,\"voucher_number\":\"SYN/PR/0001\",\"account_id\":9101,\"account_name\":\"Synthetic Supplier\",\"gst_number\":\"SYNTHETICGST1\",\"mobile_number\":\"910000000001\",\"purchase_type_id\":9312,\"purchase_type_name\":\"Synthetic Purchase Type\",\"total_amount\":472.12,\"purchase_amount\":400.1,\"taxable_amount\":400.1,\"igst_amount\":72.02,\"cgst_amount\":0,\"sgst_amount\":0,\"other_amount\":0,\"material_center_id\":9601,\"material_center_name\":\"Synthetic Store\",\"payment_amount\":0,\"status\":\"Cancelled\"}],\"summary\":{\"total_amount_total\":472.12,\"purchase_amount_total\":400.1,\"taxable_amount_total\":400.1,\"igst_amount_total\":72.02,\"cgst_amount_total\":0,\"sgst_amount_total\":0,\"other_amount_total\":0,\"payment_amount_total\":0,\"total_tax_amount_total\":72.02}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.registers.purchase-return\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"fromDate\":\"2025-06-01\",\"toDate\":\"2025-06-30\",\"page\":1,\"pageSize\":100,\"totalRows\":1,\"rowCount\":1,\"hasMore\":false,\"elapsedMs\":14,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"5b06d140-ac92-219e-b83e-350a5c9ad4fe"},{"name":"busy.registers.payment – Payment register","id":"0f086deb-118c-1243-fcdd-a95c5f893c4f","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/payment-register","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/payment-register</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.registers.payment</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.registers.payment</code></strong> (BusyNotify <code>POST /v1/payment-register</code>). One row per paid account line (record type 1, amount below zero) of the payment vouchers (type 19, transaction type not 1) in the range; the mode is the voucher's first account line on the other side. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }</code> — one date alone is that one day; neither date is the whole year.</p>\n<p><code>gst_nature</code> is <code>Not Applicable</code> for 0, else the number; the voucher's GST (unsigned) is shown on each of its rows and the summary adds the row values, as the reference. <code>instrument_type</code> from <code>I2</code>: 0 blank, 1 Cheque, 2 NEFT, 3 RTGS, 4 IMPS, 5 UPI, else the number. An address row repeated for an account never repeats a row; differing ones are <code>422</code>.</p>\n<p>Response (200): <code>data</code> = <code>{ rows: [{ date, voucher_code, voucher_type_id, voucher_number, gst_nature_id, gst_nature, mode_id, mode_name, account_id, account_name, mobile_number, amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, short_narration, instrument_type_id, instrument_type, instrument_number }], summary: { amount_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total } }</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5j.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","payment-register"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"a2e1b503-410a-33d2-9953-823ef657c380","name":"200 – synthetic payment","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/payment-register","description":"**Local** · `POST {{baseUrl}}/api/v1/payment-register` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.registers.payment`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.registers.payment`** (BusyNotify `POST /v1/payment-register`). One row per paid account line (record type 1, amount below zero) of the payment vouchers (type 19, transaction type not 1) in the range; the mode is the voucher's first account line on the other side. **Read only. Financial data.**\n\nRequest: `{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }` — one date alone is that one day; neither date is the whole year.\n\n`gst_nature` is `Not Applicable` for 0, else the number; the voucher's GST (unsigned) is shown on each of its rows and the summary adds the row values, as the reference. `instrument_type` from `I2`: 0 blank, 1 Cheque, 2 NEFT, 3 RTGS, 4 IMPS, 5 UPI, else the number. An address row repeated for an account never repeats a row; differing ones are `422`.\n\nResponse (200): `data` = `{ rows: [{ date, voucher_code, voucher_type_id, voucher_number, gst_nature_id, gst_nature, mode_id, mode_name, account_id, account_name, mobile_number, amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, short_narration, instrument_type_id, instrument_type, instrument_number }], summary: { amount_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total } }`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5j."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"rows\":[{\"date\":\"09-06-2025\",\"voucher_code\":97581,\"voucher_type_id\":19,\"voucher_number\":\"SYN/PAY/0001\",\"gst_nature_id\":0,\"gst_nature\":\"Not Applicable\",\"mode_id\":9801,\"mode_name\":\"Synthetic Bank\",\"account_id\":9101,\"account_name\":\"Synthetic Supplier\",\"mobile_number\":\"910000000001\",\"amount\":5003.25,\"taxable_amount\":0,\"igst_amount\":0,\"cgst_amount\":0,\"sgst_amount\":0,\"short_narration\":\"Synthetic payment\",\"instrument_type_id\":2,\"instrument_type\":\"NEFT\",\"instrument_number\":\"SYNNEFT0001\"}],\"summary\":{\"amount_total\":5003.25,\"taxable_amount_total\":0,\"igst_amount_total\":0,\"cgst_amount_total\":0,\"sgst_amount_total\":0}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.registers.payment\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"fromDate\":\"2025-06-01\",\"toDate\":\"2025-06-30\",\"page\":1,\"pageSize\":100,\"totalRows\":1,\"rowCount\":1,\"hasMore\":false,\"elapsedMs\":14,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"0f086deb-118c-1243-fcdd-a95c5f893c4f"},{"name":"busy.registers.receipt – Receipt register","id":"ec4f970f-74ac-c4ce-3b31-51bc84fac1ab","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/receipt-register","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/receipt-register</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.registers.receipt</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.registers.receipt</code></strong> (BusyNotify <code>POST /v1/receipt-register</code>). One row per paying account line (record type 1, amount above zero) of the receipt vouchers (type 14, transaction type not 1) in the range; the mode is the voucher's first account line on the other side. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }</code> — one date alone is that one day; neither date is the whole year.</p>\n<p>Instruments as the payment register (0 blank, 1 Cheque, 2 NEFT, 3 RTGS, 4 IMPS, 5 UPI, else the number). Several identical address rows never repeat a row; differing ones are <code>422</code>.</p>\n<p>Response (200): <code>data</code> = <code>{ rows: [{ date, voucher_code, voucher_type_id, voucher_number, gst_nature_id, gst_nature, mode_id, mode_name, account_id, account_name, mobile_number, amount, short_narration, instrument_type_id, instrument_type, instrument_number }], summary: { amount_total } }</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5j.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","receipt-register"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"40de621b-6554-223c-a30d-e251c33bae1e","name":"200 – synthetic receipt","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/receipt-register","description":"**Local** · `POST {{baseUrl}}/api/v1/receipt-register` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.registers.receipt`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.registers.receipt`** (BusyNotify `POST /v1/receipt-register`). One row per paying account line (record type 1, amount above zero) of the receipt vouchers (type 14, transaction type not 1) in the range; the mode is the voucher's first account line on the other side. **Read only. Financial data.**\n\nRequest: `{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }` — one date alone is that one day; neither date is the whole year.\n\nInstruments as the payment register (0 blank, 1 Cheque, 2 NEFT, 3 RTGS, 4 IMPS, 5 UPI, else the number). Several identical address rows never repeat a row; differing ones are `422`.\n\nResponse (200): `data` = `{ rows: [{ date, voucher_code, voucher_type_id, voucher_number, gst_nature_id, gst_nature, mode_id, mode_name, account_id, account_name, mobile_number, amount, short_narration, instrument_type_id, instrument_type, instrument_number }], summary: { amount_total } }`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5j."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"rows\":[{\"date\":\"10-06-2025\",\"voucher_code\":97591,\"voucher_type_id\":14,\"voucher_number\":\"SYN/REC/0001\",\"gst_nature_id\":0,\"gst_nature\":\"Not Applicable\",\"mode_id\":9802,\"mode_name\":\"Synthetic Cash\",\"account_id\":7001,\"account_name\":\"Synthetic Customer\",\"mobile_number\":\"910000000000\",\"amount\":750.5,\"short_narration\":\"Synthetic receipt\",\"instrument_type_id\":5,\"instrument_type\":\"UPI\",\"instrument_number\":\"SYNUPI0001\"}],\"summary\":{\"amount_total\":750.5}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.registers.receipt\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"fromDate\":\"2025-06-01\",\"toDate\":\"2025-06-30\",\"page\":1,\"pageSize\":100,\"totalRows\":1,\"rowCount\":1,\"hasMore\":false,\"elapsedMs\":14,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"ec4f970f-74ac-c4ce-3b31-51bc84fac1ab"},{"name":"busy.registers.journal – Journal register","id":"215a1cc0-0866-eb13-8929-e62462d54629","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/journal-register","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/journal-register</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.registers.journal</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.registers.journal</code></strong> (BusyNotify <code>POST /v1/journal-register</code>). Every journal line (type 16, record type 1) dated in the range, each exactly once: debit for a negative amount, credit for a positive one; <code>line_srno</code> the line number, <code>voucher_line_no</code> its position in the voucher. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }</code> — one date alone is that one day; neither date is the whole year.</p>\n<p>The voucher's GST nature and GST repeat on each of its lines and the summary adds them per line, as the reference's tests fix. Instrument names (the reference's journal mapping): 1 RTGS, 2 NEFT, 3 Cheque, 4 IMPS, 5 UPI, else the number. The number is the line's, else the voucher header's.</p>\n<p>Response (200): <code>data</code> = <code>{ rows: [{ date, voucher_code, voucher_type_id, voucher_number, line_srno, voucher_line_no, gst_nature_id, gst_nature, account_id, account_name, mobile_number, debit_amount, credit_amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, short_narration, instrument_type_id, instrument_type, instrument_number }], summary: { debit_total, credit_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total } }</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5j.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","journal-register"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"afe81755-d24f-a389-43b1-d5e793456fdf","name":"200 – synthetic journal","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/journal-register","description":"**Local** · `POST {{baseUrl}}/api/v1/journal-register` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.registers.journal`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.registers.journal`** (BusyNotify `POST /v1/journal-register`). Every journal line (type 16, record type 1) dated in the range, each exactly once: debit for a negative amount, credit for a positive one; `line_srno` the line number, `voucher_line_no` its position in the voucher. **Read only. Financial data.**\n\nRequest: `{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }` — one date alone is that one day; neither date is the whole year.\n\nThe voucher's GST nature and GST repeat on each of its lines and the summary adds them per line, as the reference's tests fix. Instrument names (the reference's journal mapping): 1 RTGS, 2 NEFT, 3 Cheque, 4 IMPS, 5 UPI, else the number. The number is the line's, else the voucher header's.\n\nResponse (200): `data` = `{ rows: [{ date, voucher_code, voucher_type_id, voucher_number, line_srno, voucher_line_no, gst_nature_id, gst_nature, account_id, account_name, mobile_number, debit_amount, credit_amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, short_narration, instrument_type_id, instrument_type, instrument_number }], summary: { debit_total, credit_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total } }`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5j."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"rows\":[{\"date\":\"12-06-2025\",\"voucher_code\":97601,\"voucher_type_id\":16,\"voucher_number\":\"SYN/JRN/0001\",\"line_srno\":1,\"voucher_line_no\":1,\"gst_nature_id\":0,\"gst_nature\":\"Not Applicable\",\"account_id\":9101,\"account_name\":\"Synthetic Supplier\",\"mobile_number\":\"910000000001\",\"debit_amount\":300.75,\"credit_amount\":0,\"taxable_amount\":0,\"igst_amount\":0,\"cgst_amount\":0,\"sgst_amount\":0,\"short_narration\":\"Synthetic journal debit\",\"instrument_type_id\":0,\"instrument_type\":\"\",\"instrument_number\":\"\"},{\"date\":\"12-06-2025\",\"voucher_code\":97601,\"voucher_type_id\":16,\"voucher_number\":\"SYN/JRN/0001\",\"line_srno\":2,\"voucher_line_no\":2,\"gst_nature_id\":0,\"gst_nature\":\"Not Applicable\",\"account_id\":9803,\"account_name\":\"Synthetic Expense\",\"mobile_number\":\"\",\"debit_amount\":0,\"credit_amount\":300.75,\"taxable_amount\":0,\"igst_amount\":0,\"cgst_amount\":0,\"sgst_amount\":0,\"short_narration\":\"Synthetic journal credit\",\"instrument_type_id\":0,\"instrument_type\":\"\",\"instrument_number\":\"\"}],\"summary\":{\"debit_total\":300.75,\"credit_total\":300.75,\"taxable_amount_total\":0,\"igst_amount_total\":0,\"cgst_amount_total\":0,\"sgst_amount_total\":0}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.registers.journal\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"fromDate\":\"2025-06-01\",\"toDate\":\"2025-06-30\",\"page\":1,\"pageSize\":100,\"totalRows\":2,\"rowCount\":2,\"hasMore\":false,\"elapsedMs\":14,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"215a1cc0-0866-eb13-8929-e62462d54629"},{"name":"busy.registers.contra – Contra register","id":"d9373530-6e5f-f810-84ab-60fd2c0919b6","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/contra-register","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/contra-register</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.registers.contra</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.registers.contra</code></strong> (BusyNotify <code>POST /v1/contra-register</code>). Every contra line (type 15, record type 1: cash and bank transfers) dated in the range, each exactly once, with debit or credit, narration and instrument. <strong>Read only. Financial data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }</code> — one date alone is that one day; neither date is the whole year.</p>\n<p>Instrument names (the reference's contra mapping): 1 RTGS, 2 NEFT, 3 Cheque, 4 IMPS, 5 UPI, 9 IMPS, 11 Transfer, else the number.</p>\n<p>Response (200): <code>data</code> = <code>{ rows: [{ date, voucher_code, voucher_type_id, voucher_number, line_srno, voucher_line_no, account_id, account_name, mobile_number, debit_amount, credit_amount, short_narration, instrument_type_id, instrument_type, instrument_number }], summary: { debit_total, credit_total } }</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5j.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","contra-register"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"adeb3a42-db65-b2be-1ef0-49f9eea0469e","name":"200 – synthetic contra","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/contra-register","description":"**Local** · `POST {{baseUrl}}/api/v1/contra-register` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.registers.contra`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.registers.contra`** (BusyNotify `POST /v1/contra-register`). Every contra line (type 15, record type 1: cash and bank transfers) dated in the range, each exactly once, with debit or credit, narration and instrument. **Read only. Financial data.**\n\nRequest: `{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }` — one date alone is that one day; neither date is the whole year.\n\nInstrument names (the reference's contra mapping): 1 RTGS, 2 NEFT, 3 Cheque, 4 IMPS, 5 UPI, 9 IMPS, 11 Transfer, else the number.\n\nResponse (200): `data` = `{ rows: [{ date, voucher_code, voucher_type_id, voucher_number, line_srno, voucher_line_no, account_id, account_name, mobile_number, debit_amount, credit_amount, short_narration, instrument_type_id, instrument_type, instrument_number }], summary: { debit_total, credit_total } }`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5j."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"rows\":[{\"date\":\"15-06-2025\",\"voucher_code\":97611,\"voucher_type_id\":15,\"voucher_number\":\"SYN/CTR/0001\",\"line_srno\":1,\"voucher_line_no\":1,\"account_id\":9801,\"account_name\":\"Synthetic Bank\",\"mobile_number\":\"\",\"debit_amount\":1503.3,\"credit_amount\":0,\"short_narration\":\"Synthetic deposit\",\"instrument_type_id\":11,\"instrument_type\":\"Transfer\",\"instrument_number\":\"SYNTRF0001\"},{\"date\":\"15-06-2025\",\"voucher_code\":97611,\"voucher_type_id\":15,\"voucher_number\":\"SYN/CTR/0001\",\"line_srno\":2,\"voucher_line_no\":2,\"account_id\":9802,\"account_name\":\"Synthetic Cash\",\"mobile_number\":\"\",\"debit_amount\":0,\"credit_amount\":1503.3,\"short_narration\":\"Synthetic deposit\",\"instrument_type_id\":0,\"instrument_type\":\"\",\"instrument_number\":\"\"}],\"summary\":{\"debit_total\":1503.3,\"credit_total\":1503.3}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.registers.contra\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"fromDate\":\"2025-06-01\",\"toDate\":\"2025-06-30\",\"page\":1,\"pageSize\":100,\"totalRows\":2,\"rowCount\":2,\"hasMore\":false,\"elapsedMs\":14,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"d9373530-6e5f-f810-84ab-60fd2c0919b6"},{"name":"busy.sales-orders.pending – Pending sales orders","id":"fec16f87-0e18-66c6-9115-367fb4dacbe4","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"statusField\": \"OF1\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/pending-sales-orders","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/pending-sales-orders</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.sales-orders.pending</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.sales-orders.pending</code></strong> (BusyNotify <code>POST /v1/pending-sales-orders</code>). One customer's sales-order items still pending: the exact <code>RefCode</code> lifecycle (no FIFO; a dispatch of another customer never counts), carried-forward orders (type 1, code -1200), product stock (movement + opening) and an optional status field. <strong>Read only. Customer and order data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, customerId, referenceNumber?, statusField?, page?, pageSize? }</code>.</p>\n<ul>\n<li><code>customerId</code>: required, 1–2147483647.</li>\n<li><code>referenceNumber</code>: optional, trimmed, at most 200 characters; matches the order's trimmed number or its reference code exactly. Never echoed (<code>metadata.referenceNumberApplied</code> is true/false).</li>\n<li><code>statusField</code>: optional, exactly <code>OF1</code> … <code>OF10</code> after trimming (case-insensitive); anything else is <code>400 INVALID_PARAMETER</code> (<code>field: statusField</code>). The status is that optional voucher field read as an integer and the master of that code.</li>\n<li>Pages: default 1 / 100, maximum 500.</li>\n</ul>\n<p>Response (200): <code>data</code> = <code>[{ sales_order_refcode, reference_no, order_date, due_date, customer_id, customer_name, product_id, product_name, unit_id, unit_name, status_id, status, total_qty, pending_qty, product_stock }]</code>, only rows still pending.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5k.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","pending-sales-orders"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"847de5f9-ef93-39c7-4a02-677e9fdc8074","name":"200 – synthetic pending sales orders","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"statusField\": \"OF1\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/pending-sales-orders","description":"**Local** · `POST {{baseUrl}}/api/v1/pending-sales-orders` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear`, `customerId` · operation `busy.sales-orders.pending`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.sales-orders.pending`** (BusyNotify `POST /v1/pending-sales-orders`). One customer's sales-order items still pending: the exact `RefCode` lifecycle (no FIFO; a dispatch of another customer never counts), carried-forward orders (type 1, code -1200), product stock (movement + opening) and an optional status field. **Read only. Customer and order data.**\n\nRequest: `{ companyCode, financialYear, customerId, referenceNumber?, statusField?, page?, pageSize? }`.\n- `customerId`: required, 1–2147483647.\n- `referenceNumber`: optional, trimmed, at most 200 characters; matches the order's trimmed number or its reference code exactly. Never echoed (`metadata.referenceNumberApplied` is true/false).\n- `statusField`: optional, exactly `OF1` … `OF10` after trimming (case-insensitive); anything else is `400 INVALID_PARAMETER` (`field: statusField`). The status is that optional voucher field read as an integer and the master of that code.\n- Pages: default 1 / 100, maximum 500.\n\nResponse (200): `data` = `[{ sales_order_refcode, reference_no, order_date, due_date, customer_id, customer_name, product_id, product_name, unit_id, unit_name, status_id, status, total_qty, pending_qty, product_stock }]`, only rows still pending.\n\nCanonical contract: `docs/LOCAL-API.md` section 5k."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":[{\"sales_order_refcode\":98311,\"reference_no\":\"SYN/SO/0001\",\"order_date\":\"2025-06-04\",\"due_date\":\"2025-06-18\",\"customer_id\":7001,\"customer_name\":\"Synthetic Customer\",\"product_id\":9401,\"product_name\":\"Synthetic Item\",\"unit_id\":9701,\"unit_name\":\"Pcs\",\"status_id\":9901,\"status\":\"Synthetic Status\",\"total_qty\":7.25,\"pending_qty\":3.75,\"product_stock\":41.5}],\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.sales-orders.pending\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"customerId\":7001,\"referenceNumberApplied\":false,\"statusField\":\"OF1\",\"page\":1,\"pageSize\":100,\"totalRows\":1,\"rowCount\":1,\"hasMore\":false,\"elapsedMs\":16,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"fec16f87-0e18-66c6-9115-367fb4dacbe4"},{"name":"busy.sales-orders.pending-vouchers – Pending sales order vouchers","id":"71de0d26-9096-4a4c-773c-3bd600d129a8","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/pending-sales-order-vouchers","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/pending-sales-order-vouchers</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.sales-orders.pending-vouchers</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.sales-orders.pending-vouchers</code></strong> (BusyNotify <code>POST /v1/pending-sales-order-vouchers</code>). One customer's pending sales orders summed per voucher: ordered, dispatched (ordered − pending) and pending quantities, the voucher's material centre and an optional status field. Different vouchers that share an order number stay separate rows. <strong>Read only. Customer and order data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, customerId, statusField?, page?, pageSize? }</code> — <code>statusField</code> exactly <code>OF1</code> … <code>OF10</code>; no <code>referenceNumber</code> here (unknown members are <code>400 BAD_REQUEST</code>).</p>\n<p>Response (200): <code>data</code> = <code>[{ sales_order_refcode, sales_order_vch_code, sales_order_number, order_date, due_date, customer_id, customer_name, material_center_id, material_center_name, status_id, status, total_ordered_qty, total_dispatched_qty, total_pending_qty }]</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5k.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","pending-sales-order-vouchers"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"beb4bcab-621d-8271-4c68-0985179dc9f7","name":"200 – synthetic pending order vouchers","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/pending-sales-order-vouchers","description":"**Local** · `POST {{baseUrl}}/api/v1/pending-sales-order-vouchers` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear`, `customerId` · operation `busy.sales-orders.pending-vouchers`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.sales-orders.pending-vouchers`** (BusyNotify `POST /v1/pending-sales-order-vouchers`). One customer's pending sales orders summed per voucher: ordered, dispatched (ordered − pending) and pending quantities, the voucher's material centre and an optional status field. Different vouchers that share an order number stay separate rows. **Read only. Customer and order data.**\n\nRequest: `{ companyCode, financialYear, customerId, statusField?, page?, pageSize? }` — `statusField` exactly `OF1` … `OF10`; no `referenceNumber` here (unknown members are `400 BAD_REQUEST`).\n\nResponse (200): `data` = `[{ sales_order_refcode, sales_order_vch_code, sales_order_number, order_date, due_date, customer_id, customer_name, material_center_id, material_center_name, status_id, status, total_ordered_qty, total_dispatched_qty, total_pending_qty }]`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5k."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":[{\"sales_order_refcode\":98311,\"sales_order_vch_code\":97811,\"sales_order_number\":\"SYN/SO/0001\",\"order_date\":\"2025-06-04\",\"due_date\":\"2025-06-18\",\"customer_id\":7001,\"customer_name\":\"Synthetic Customer\",\"material_center_id\":9601,\"material_center_name\":\"Synthetic Store\",\"status_id\":null,\"status\":null,\"total_ordered_qty\":11.75,\"total_dispatched_qty\":5.25,\"total_pending_qty\":6.5}],\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.sales-orders.pending-vouchers\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"customerId\":7001,\"statusField\":null,\"page\":1,\"pageSize\":100,\"totalRows\":1,\"rowCount\":1,\"hasMore\":false,\"elapsedMs\":13,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"71de0d26-9096-4a4c-773c-3bd600d129a8"},{"name":"busy.sales.invoices – All sale invoices","id":"fe4395d0-85cf-0ed6-2459-714bb1860868","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"startDate\": \"{{financialYear}}-04-01\",\n  \"endDate\": \"{{financialYear}}-06-30\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/all-sale-invoices","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/all-sale-invoices</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>startDate</code>, <code>endDate</code> · operation <code>busy.sales.invoices</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.sales.invoices</code></strong> (BusyNotify <code>POST /v1/all-sale-invoices</code>). Sale invoices (type 9) of a date range, latest first, with customer, group, address, billing, salesman, transport, e-way and e-invoice details, the latest voucher action and the payment status of the invoice's own bill references. <strong>Read only. Customer and invoice data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, startDate, endDate, customerId?, materialCenterId?, materialCenterGroupId?, page?, pageSize? }</code> — both dates required (<code>YYYY-MM-DD</code> inside the April–March year; start not after end); the group filter is the material centre's parent group. Pages: default 1 / 100, maximum 500.</p>\n<p>Response (200): <code>data</code> = 40-member rows in the reference's order; <code>total_amount</code> and <code>grand_total</code> are two-decimal <strong>strings</strong> (the reference's <code>printf('%.2f')</code>); <code>payment_status</code> is <code>Not Tracked</code>, <code>Paid</code>, <code>Partially Paid</code> or <code>Unpaid</code>; <code>date</code> is <code>DD-MM-YYYY</code>. Differing address, billing or other-information rows are <code>422 BUSY_DATA_INCONSISTENT</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5k.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","all-sale-invoices"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"3f59f408-0b55-e6f0-8a3f-9a1097089a9e","name":"200 – synthetic sale invoices","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"startDate\": \"{{financialYear}}-04-01\",\n  \"endDate\": \"{{financialYear}}-06-30\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/all-sale-invoices","description":"**Local** · `POST {{baseUrl}}/api/v1/all-sale-invoices` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear`, `startDate`, `endDate` · operation `busy.sales.invoices`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.sales.invoices`** (BusyNotify `POST /v1/all-sale-invoices`). Sale invoices (type 9) of a date range, latest first, with customer, group, address, billing, salesman, transport, e-way and e-invoice details, the latest voucher action and the payment status of the invoice's own bill references. **Read only. Customer and invoice data.**\n\nRequest: `{ companyCode, financialYear, startDate, endDate, customerId?, materialCenterId?, materialCenterGroupId?, page?, pageSize? }` — both dates required (`YYYY-MM-DD` inside the April–March year; start not after end); the group filter is the material centre's parent group. Pages: default 1 / 100, maximum 500.\n\nResponse (200): `data` = 40-member rows in the reference's order; `total_amount` and `grand_total` are two-decimal **strings** (the reference's `printf('%.2f')`); `payment_status` is `Not Tracked`, `Paid`, `Partially Paid` or `Unpaid`; `date` is `DD-MM-YYYY`. Differing address, billing or other-information rows are `422 BUSY_DATA_INCONSISTENT`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5k."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":[{\"vch_code\":97561,\"date\":\"02-06-2025\",\"invoice_no\":\"SYN/S/0001\",\"material_center_id\":9601,\"material_center\":\"Synthetic Store\",\"material_center_group_id\":9611,\"material_center_group\":\"Synthetic Store Group\",\"sale_type_id\":9311,\"sale_type_name\":\"Synthetic Sale Type\",\"customer_id\":7001,\"customer_name\":\"Synthetic Customer\",\"customer_print_name\":\"Synthetic Customer\",\"customer_group_id\":7101,\"customer_group_name\":\"Synthetic Debtors\",\"gst_number\":\"SYNTHETICGST0\",\"mobile_number\":\"910000000000\",\"whatsapp_number\":\"910000000000\",\"station\":\"Synthetic Station\",\"state\":\"Synthetic State\",\"billing_name\":\"Synthetic Customer\",\"billing_gst_no\":\"SYNTHETICGST0\",\"billing_address\":\"Synthetic Street 1 Synthetic Area\",\"salesman_id\":9001,\"salesman_name\":\"Synthetic Salesman\",\"salesman_mobile_number\":\"910000000001\",\"salesman_whatsapp_number\":\"910000000001\",\"total_amount\":\"1186.30\",\"grand_total\":\"1005.34\",\"bill_reference_code\":98701,\"bill_reference_count\":1,\"payment_status\":\"Partially Paid\",\"is_paid\":\"NO\",\"paid_amount\":500.2,\"pending_amount\":686.1,\"transport\":\"Synthetic Transport\",\"vehicle_no\":\"SYN00AA0000\",\"eway_no\":\"\",\"einv_no\":\"\",\"last_action_time\":\"02-06-2025 10:15\",\"processed_by\":\"synthetic.user\"}],\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.sales.invoices\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"startDate\":\"2025-06-01\",\"endDate\":\"2025-06-30\",\"customerId\":null,\"materialCenterId\":null,\"materialCenterGroupId\":null,\"page\":1,\"pageSize\":100,\"totalRows\":1,\"rowCount\":1,\"hasMore\":false,\"elapsedMs\":21,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"fe4395d0-85cf-0ed6-2459-714bb1860868"},{"name":"busy.sales.invoices.products – Sale invoice products","id":"7482e61b-a1ce-632d-e81c-3ee894d340d6","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherId\": {{salesInvoiceVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sale-invoice-products","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/sale-invoice-products</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>voucherId</code> · operation <code>busy.sales.invoices.products</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.sales.invoices.products</code></strong> (BusyNotify <code>POST /v1/sale-invoice-products</code>). The item lines of one sale invoice with customer, material centre, sale type, product, unit, MRP, quantity (3 decimals), base and sale rates, taxable value and GST (CGST + SGST for location type 0, else IGST; several GST rows of one line are one). <strong>Read only. Invoice data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, voucherId }</code> — <code>voucherId</code> required, 1–2147483647. Not paged, as the reference.</p>\n<p>A voucher that is not a sale invoice (type 9), an unknown voucher or an invoice without item lines is <code>404 NOT_FOUND</code> (<code>field: voucherId</code>; the value is never echoed).</p>\n<p>Response (200): <code>data</code> = 34-member rows (the 33 reference members plus <code>line_description</code>) ordered by line number, then product.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5k.</p>\n<p><strong>Line descriptions (owner acceptance 2026-10-19):</strong> every line also carries <code>line_description</code> (last member): the voucher line's own description in BUSY (positions 1..n, an empty position as <code>\"\"</code>, <code>[]</code> when the line has none), joined by voucher code and line number. Public guide: <code>docs/public/api/line-descriptions.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","sale-invoice-products"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"ec745a8e-2b8a-171c-e63e-2291fb51ffc9","name":"200 – synthetic invoice products","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherId\": {{salesInvoiceVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sale-invoice-products","description":"**Local** · `POST {{baseUrl}}/api/v1/sale-invoice-products` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear`, `voucherId` · operation `busy.sales.invoices.products`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.sales.invoices.products`** (BusyNotify `POST /v1/sale-invoice-products`). The item lines of one sale invoice with customer, material centre, sale type, product, unit, MRP, quantity (3 decimals), base and sale rates, taxable value and GST (CGST + SGST for location type 0, else IGST; several GST rows of one line are one). **Read only. Invoice data.**\n\nRequest: `{ companyCode, financialYear, voucherId }` — `voucherId` required, 1–2147483647. Not paged, as the reference.\n\nA voucher that is not a sale invoice (type 9), an unknown voucher or an invoice without item lines is `404 NOT_FOUND` (`field: voucherId`; the value is never echoed).\n\nResponse (200): `data` = 34-member rows (the 33 reference members plus `line_description`) ordered by line number, then product.\n\nCanonical contract: `docs/LOCAL-API.md` section 5k.\n\n**Line descriptions (owner acceptance 2026-10-19):** every line also carries `line_description` (last member): the voucher line's own description in BUSY (positions 1..n, an empty position as `\"\"`, `[]` when the line has none), joined by voucher code and line number. Public guide: `docs/public/api/line-descriptions.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":[{\"voucher_id\":97561,\"date\":\"02-06-2025\",\"invoice_no\":\"SYN/S/0001\",\"customer_id\":7001,\"customer_name\":\"Synthetic Customer\",\"customer_alias\":\"SC\",\"material_center_id\":9601,\"material_center_name\":\"Synthetic Store\",\"sale_type_id\":9311,\"sale_type_name\":\"Synthetic Sale Type\",\"product_id\":9401,\"product_name\":\"Synthetic Item\",\"product_alias\":\"SI\",\"product_print_name\":\"SYNTHETIC ITEM\",\"product_group_id\":9501,\"product_group_name\":\"Synthetic Item Group\",\"product_hsn_code\":\"0000\",\"product_mrp\":145.25,\"quantity\":7.25,\"unit_id\":9701,\"unit_name\":\"Pcs\",\"base_rate\":138.67,\"sale_rate\":163.63,\"taxable_value\":1005.34,\"gst_percentage\":18,\"gst_amount\":180.96,\"cgst_percentage\":9,\"cgst_amount\":90.48,\"sgst_percentage\":9,\"sgst_amount\":90.48,\"igst_percentage\":0,\"igst_amount\":0,\"total_amount\":1186.3}],\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.sales.invoices.products\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"voucherId\":97561,\"rowCount\":1,\"elapsedMs\":9,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"7482e61b-a1ce-632d-e81c-3ee894d340d6"},{"name":"busy.sales.vouchers-with-items – Sale vouchers with items","id":"614d2494-8b4a-884d-205a-29b5b3934bf7","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/list-sale-vouchers-with-items","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/list-sale-vouchers-with-items</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.sales.vouchers-with-items</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.sales.vouchers-with-items</code></strong> (BusyNotify <code>POST /v1/list-sale-vouchers-with-items</code>). Every sale item line of the range with its voucher header, nested per voucher (customer, state, GST and mobile numbers, billing, material centre, approval flags; item prices, list price, net price, discount base and GST), with running voucher totals and a summary. <strong>Read only. Customer and invoice data.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }</code> — neither date is the whole financial year; one date alone (<code>fromDate</code> or <code>toDate</code>) is that one day; both are the range.</p>\n<p>Pages count <strong>vouchers</strong> (default 1 / 100, maximum 500) and never split a voucher's items; <code>summary</code> covers the whole range, never one page; <code>metadata.totalRows</code> counts vouchers.</p>\n<p>Response (200): <code>data</code> = <code>{ vouchers: [{ voucher_code, voucher_number, date, voucher_type_id, approval_status, rejection_status, customer_id, customer_name, customer_state, customer_gst_no, customer_mobile_number, customer_whatsapp_number, billing_gst_no, billing_mobile_number, material_center_id, material_center_name, total_quantity, total_amount, items: [ … ] }], summary: { total_quantity, total_amount, item_row_count, voucher_count } }</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5k.</p>\n<p><strong>Line descriptions (owner acceptance 2026-10-19):</strong> every item also carries <code>line_description</code> (its last member, 23 members): the voucher line's own description in BUSY (positions 1..n, an empty position as <code>\"\"</code>, <code>[]</code> when the line has none), joined by voucher code and line number. Public guide: <code>docs/public/api/line-descriptions.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","list-sale-vouchers-with-items"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"1dfa074c-1e2f-8512-aa1e-10314f20ec37","name":"200 – synthetic sale vouchers with items","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/list-sale-vouchers-with-items","description":"**Local** · `POST {{baseUrl}}/api/v1/list-sale-vouchers-with-items` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear` · operation `busy.sales.vouchers-with-items`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.sales.vouchers-with-items`** (BusyNotify `POST /v1/list-sale-vouchers-with-items`). Every sale item line of the range with its voucher header, nested per voucher (customer, state, GST and mobile numbers, billing, material centre, approval flags; item prices, list price, net price, discount base and GST), with running voucher totals and a summary. **Read only. Customer and invoice data.**\n\nRequest: `{ companyCode, financialYear, fromDate?, toDate?, page?, pageSize? }` — neither date is the whole financial year; one date alone (`fromDate` or `toDate`) is that one day; both are the range.\n\nPages count **vouchers** (default 1 / 100, maximum 500) and never split a voucher's items; `summary` covers the whole range, never one page; `metadata.totalRows` counts vouchers.\n\nResponse (200): `data` = `{ vouchers: [{ voucher_code, voucher_number, date, voucher_type_id, approval_status, rejection_status, customer_id, customer_name, customer_state, customer_gst_no, customer_mobile_number, customer_whatsapp_number, billing_gst_no, billing_mobile_number, material_center_id, material_center_name, total_quantity, total_amount, items: [ … ] }], summary: { total_quantity, total_amount, item_row_count, voucher_count } }`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5k.\n\n**Line descriptions (owner acceptance 2026-10-19):** every item also carries `line_description` (its last member, 23 members): the voucher line's own description in BUSY (positions 1..n, an empty position as `\"\"`, `[]` when the line has none), joined by voucher code and line number. Public guide: `docs/public/api/line-descriptions.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"vouchers\":[{\"voucher_code\":97561,\"voucher_number\":\"SYN/S/0001\",\"date\":\"02-06-2025\",\"voucher_type_id\":9,\"approval_status\":0,\"rejection_status\":0,\"customer_id\":7001,\"customer_name\":\"Synthetic Customer\",\"customer_state\":\"Synthetic State\",\"customer_gst_no\":\"SYNTHETICGST0\",\"customer_mobile_number\":\"910000000000\",\"customer_whatsapp_number\":\"910000000000\",\"billing_gst_no\":\"SYNTHETICGST0\",\"billing_mobile_number\":\"910000000000\",\"material_center_id\":9601,\"material_center_name\":\"Synthetic Store\",\"total_quantity\":7.25,\"total_amount\":1005.34,\"items\":[{\"sr_no\":1,\"product_id\":9401,\"product_name\":\"Synthetic Item\",\"product_group_id\":9501,\"product_group_name\":\"Synthetic Item Group\",\"purchase_date\":\"2025-04-01T10:00:00\",\"unit_id\":9701,\"unit_name\":\"Pcs\",\"quantity\":7.25,\"price\":138.67,\"amount\":1005.34,\"cgst_percent\":9,\"cgst_amount\":90.48,\"sgst_percent\":9,\"sgst_amount\":90.48,\"igst_percent\":0,\"igst_amount\":0,\"gst_percent\":18,\"gst_amount\":180.96,\"list_price\":145.25,\"net_price\":163.63,\"amount_before_discount\":1053.06}]}],\"summary\":{\"total_quantity\":7.25,\"total_amount\":1005.34,\"item_row_count\":1,\"voucher_count\":1}},\"metadata\":{\"apiVersion\":\"v1\",\"operation\":\"busy.sales.vouchers-with-items\",\"requestId\":\"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\"companyCode\":\"COMP0001\",\"financialYear\":\"2025\",\"fromDate\":\"2025-06-01\",\"toDate\":\"2025-06-30\",\"page\":1,\"pageSize\":100,\"totalRows\":1,\"rowCount\":1,\"hasMore\":false,\"elapsedMs\":18,\"executedAt\":\"2026-09-26T10:00:00+00:00\"}}"}],"_postman_id":"614d2494-8b4a-884d-205a-29b5b3934bf7"}],"id":"4bc4bb0f-93db-4cf7-a7cd-e42430f4d346","description":"<p>The accounting registers, purchase and sales order and invoice reads. Read only; writing a sales order is in ⚠ Voucher Create. These are POST requests only because they carry a JSON body; none of them changes BUSY or AI Zeny.</p>\n","_postman_id":"4bc4bb0f-93db-4cf7-a7cd-e42430f4d346","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ Voucher PDFs — BUSY print flag changes","item":[{"name":"⚠ busy.vouchers.pdf – Sales invoice PDF","id":"d1cb87d6-85c3-37f1-7282-700a14fbfe2f","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"salesInvoice\",\n  \"voucherId\": {{salesInvoiceVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /api/v1/voucher-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (<code>DocPrinted</code>).</p>\n<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/voucher-pdf</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · ⚠ BUSY marks the voucher printed\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>voucherType</code> · operation <code>busy.vouchers.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.vouchers.pdf</code></strong> (<code>POST /api/v1/voucher-pdf</code>). One existing BUSY voucher printed by <strong>BUSY's own printing</strong> on this PC and returned as a PDF in <code>data.contentBase64</code> (standard base64). This request prints a <strong>sales invoice</strong>; the requests below it print the other types through the same route. <strong>AI Zeny creates no accounting voucher in this request</strong>, but like printing in BUSY, BUSY marks the printed voucher as printed (its <code>DocPrinted</code> flag); nothing else in the books changes.</p>\n<p><strong><code>voucherType</code></strong> (exact, case-sensitive): <code>salesInvoice</code>, <code>salesReturn</code>, <code>receipt</code>, <code>purchaseInvoice</code>, <code>purchaseReturn</code>, <code>payment</code>. Any other value is <code>400 INVALID_PARAMETER</code> (<code>field: voucherType</code>).</p>\n<p>Request: <code>{ companyCode, financialYear, voucherType, voucherId | voucherNumber, formatName? }</code></p>\n<ul>\n<li>Exactly one of <code>voucherId</code> (BUSY's voucher code, 1–2147483647) and <code>voucherNumber</code> (as BUSY shows it, 1–50 characters, matched exactly including case). The voucher is looked up <strong>only among vouchers of that type</strong>: a sales return and a sales invoice can share a number (<code>1/2026-27</code> on COMP0002); another type's code is <code>404</code>.</li>\n<li><code>formatName</code>: one of the company's BUSY print formats <strong>for that voucher type</strong>, exactly as named (<code>STANDARD</code>, not <code>Standard</code>). Left out = BUSY's default for the type (<code>STANDARD</code>); if the company has no STANDARD format for the type, <code>409 BUSY_PRINT_FORMAT_MISSING</code> and nothing is printed (BUSY would create the format while printing).</li>\n</ul>\n<p>Response (200): <code>data</code> = <code>{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }</code>; <code>fileName</code> starts with the type (<code>SalesInvoice-</code>, <code>SalesReturn-</code>, <code>Receipt-</code>, <code>PurchaseInvoice-</code>, <code>PurchaseReturn-</code>, <code>Payment-</code>). <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, voucherType, lookup, voucherId, voucherNumber, voucherDate, formatSource (busyDefault | selected), formatName, elapsedMs, executedAt</code>.</p>\n<p>Errors: <code>400 INVALID_PARAMETER</code> / <code>BAD_REQUEST</code>; <code>404 NOT_FOUND</code> (<code>field</code> voucherId, voucherNumber or formatName — the message lists the type's formats); <code>409 BUSY_PRINT_FORMAT_MISSING</code>; <code>422 BUSY_DATA_INCONSISTENT</code> (several vouchers of the type share the number: send voucherId), <code>RESULT_TOO_LARGE</code> (over 1 MiB), <code>BUSY_COM_PDF_BLANK</code>; <code>409 BUSY_COM_SIGN_IN_UNSUPPORTED</code>; <code>502 BUSY_COM_*</code> print failures; <code>503</code> PC prerequisites (<code>BUSY_COM_DEFAULT_PRINTER_MISSING</code> …) and <code>BUSY_COM_QUEUE_TIMEOUT</code>; <code>504 BUSY_COM_TIMEOUT</code>. One PDF at a time, up to 2 minutes each: give the request a long timeout.</p>\n<p>Cloud: all six types are also relayed through <code>{{cloudBaseUrl}}/v1/voucher-pdf</code> (cloud <code>3b13ab1</code>; see Cloud Relay → Voucher PDFs), and the current Windows build runs them.</p>\n<p><em>Saved examples: <code>salesOrder</code> remains an unsupported voucher type for this PDF route; use one of the six documented types.</em></p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5aa.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","voucher-pdf"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"0feed67a-7593-150c-2c90-89d44da7506d","name":"200 – sales invoice PDF (synthetic example)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"salesInvoice\",\n  \"voucherId\": {{salesInvoiceVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/voucher-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (`DocPrinted`).\n\n**Local** · `POST {{baseUrl}}/api/v1/voucher-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ BUSY marks the voucher printed\n**Required:** `companyCode`, `financialYear`, `voucherType` · operation `busy.vouchers.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.vouchers.pdf`** (`POST /api/v1/voucher-pdf`). One existing BUSY voucher printed by **BUSY's own printing** on this PC and returned as a PDF in `data.contentBase64` (standard base64). This request prints a **sales invoice**; the requests below it print the other types through the same route. **AI Zeny creates no accounting voucher in this request**, but like printing in BUSY, BUSY marks the printed voucher as printed (its `DocPrinted` flag); nothing else in the books changes.\n\n**`voucherType`** (exact, case-sensitive): `salesInvoice`, `salesReturn`, `receipt`, `purchaseInvoice`, `purchaseReturn`, `payment`. Any other value is `400 INVALID_PARAMETER` (`field: voucherType`).\n\nRequest: `{ companyCode, financialYear, voucherType, voucherId | voucherNumber, formatName? }`\n- Exactly one of `voucherId` (BUSY's voucher code, 1–2147483647) and `voucherNumber` (as BUSY shows it, 1–50 characters, matched exactly including case). The voucher is looked up **only among vouchers of that type**: a sales return and a sales invoice can share a number (`1/2026-27` on COMP0002); another type's code is `404`.\n- `formatName`: one of the company's BUSY print formats **for that voucher type**, exactly as named (`STANDARD`, not `Standard`). Left out = BUSY's default for the type (`STANDARD`); if the company has no STANDARD format for the type, `409 BUSY_PRINT_FORMAT_MISSING` and nothing is printed (BUSY would create the format while printing).\n\nResponse (200): `data` = `{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }`; `fileName` starts with the type (`SalesInvoice-`, `SalesReturn-`, `Receipt-`, `PurchaseInvoice-`, `PurchaseReturn-`, `Payment-`). `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, voucherType, lookup, voucherId, voucherNumber, voucherDate, formatSource (busyDefault | selected), formatName, elapsedMs, executedAt`.\n\nErrors: `400 INVALID_PARAMETER` / `BAD_REQUEST`; `404 NOT_FOUND` (`field` voucherId, voucherNumber or formatName — the message lists the type's formats); `409 BUSY_PRINT_FORMAT_MISSING`; `422 BUSY_DATA_INCONSISTENT` (several vouchers of the type share the number: send voucherId), `RESULT_TOO_LARGE` (over 1 MiB), `BUSY_COM_PDF_BLANK`; `409 BUSY_COM_SIGN_IN_UNSUPPORTED`; `502 BUSY_COM_*` print failures; `503` PC prerequisites (`BUSY_COM_DEFAULT_PRINTER_MISSING` …) and `BUSY_COM_QUEUE_TIMEOUT`; `504 BUSY_COM_TIMEOUT`. One PDF at a time, up to 2 minutes each: give the request a long timeout.\n\nCloud: all six types are also relayed through `{{cloudBaseUrl}}/v1/voucher-pdf` (cloud `3b13ab1`; see Cloud Relay → Voucher PDFs), and the current Windows build runs them.\n\n_Saved examples: `salesOrder` remains an unsupported voucher type for this PDF route; use one of the six documented types._\n\nCanonical contract: `docs/LOCAL-API.md` section 5aa."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"fileName\": \"SalesInvoice-COMP0001-2025-SYN-S-0001.pdf\",\n    \"mimeType\": \"application/pdf\",\n    \"byteLength\": 55,\n    \"sha256\": \"09a60e6e466d300dde053aaf30a656d7869cb67111bcf9353e097056aef29148\",\n    \"pages\": 1,\n    \"contentBase64\": \"JVBERi0xLjQKJSBzeW50aGV0aWMgZXhhbXBsZSwgbm90IGEgcmVhbCBpbnZvaWNlCiUlRU9GCg==\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.vouchers.pdf\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2025\",\n    \"voucherType\": \"salesInvoice\",\n    \"lookup\": \"voucherId\",\n    \"voucherId\": 97561,\n    \"voucherNumber\": \"SYN/S/0001\",\n    \"voucherDate\": \"2025-06-02\",\n    \"formatSource\": \"busyDefault\",\n    \"formatName\": null,\n    \"elapsedMs\": 6210,\n    \"executedAt\": \"2026-09-26T10:00:00+00:00\"\n  }\n}"},{"id":"1dabf205-3f33-891e-8e27-38f01c9f0fe7","name":"400 – voucher type not supported (salesOrder)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"salesInvoice\",\n  \"voucherId\": {{salesInvoiceVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/voucher-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (`DocPrinted`).\n\n**Local** · `POST {{baseUrl}}/api/v1/voucher-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ BUSY marks the voucher printed\n**Required:** `companyCode`, `financialYear`, `voucherType` · operation `busy.vouchers.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.vouchers.pdf`** (`POST /api/v1/voucher-pdf`). One existing BUSY voucher printed by **BUSY's own printing** on this PC and returned as a PDF in `data.contentBase64` (standard base64). This request prints a **sales invoice**; the requests below it print the other types through the same route. **AI Zeny creates no accounting voucher in this request**, but like printing in BUSY, BUSY marks the printed voucher as printed (its `DocPrinted` flag); nothing else in the books changes.\n\n**`voucherType`** (exact, case-sensitive): `salesInvoice`, `salesReturn`, `receipt`, `purchaseInvoice`, `purchaseReturn`, `payment`. Any other value is `400 INVALID_PARAMETER` (`field: voucherType`).\n\nRequest: `{ companyCode, financialYear, voucherType, voucherId | voucherNumber, formatName? }`\n- Exactly one of `voucherId` (BUSY's voucher code, 1–2147483647) and `voucherNumber` (as BUSY shows it, 1–50 characters, matched exactly including case). The voucher is looked up **only among vouchers of that type**: a sales return and a sales invoice can share a number (`1/2026-27` on COMP0002); another type's code is `404`.\n- `formatName`: one of the company's BUSY print formats **for that voucher type**, exactly as named (`STANDARD`, not `Standard`). Left out = BUSY's default for the type (`STANDARD`); if the company has no STANDARD format for the type, `409 BUSY_PRINT_FORMAT_MISSING` and nothing is printed (BUSY would create the format while printing).\n\nResponse (200): `data` = `{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }`; `fileName` starts with the type (`SalesInvoice-`, `SalesReturn-`, `Receipt-`, `PurchaseInvoice-`, `PurchaseReturn-`, `Payment-`). `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, voucherType, lookup, voucherId, voucherNumber, voucherDate, formatSource (busyDefault | selected), formatName, elapsedMs, executedAt`.\n\nErrors: `400 INVALID_PARAMETER` / `BAD_REQUEST`; `404 NOT_FOUND` (`field` voucherId, voucherNumber or formatName — the message lists the type's formats); `409 BUSY_PRINT_FORMAT_MISSING`; `422 BUSY_DATA_INCONSISTENT` (several vouchers of the type share the number: send voucherId), `RESULT_TOO_LARGE` (over 1 MiB), `BUSY_COM_PDF_BLANK`; `409 BUSY_COM_SIGN_IN_UNSUPPORTED`; `502 BUSY_COM_*` print failures; `503` PC prerequisites (`BUSY_COM_DEFAULT_PRINTER_MISSING` …) and `BUSY_COM_QUEUE_TIMEOUT`; `504 BUSY_COM_TIMEOUT`. One PDF at a time, up to 2 minutes each: give the request a long timeout.\n\nCloud: all six types are also relayed through `{{cloudBaseUrl}}/v1/voucher-pdf` (cloud `3b13ab1`; see Cloud Relay → Voucher PDFs), and the current Windows build runs them.\n\n_Saved examples: `salesOrder` remains an unsupported voucher type for this PDF route; use one of the six documented types._\n\nCanonical contract: `docs/LOCAL-API.md` section 5aa."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e12","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"That voucherType is not supported. This version prints salesInvoice, salesReturn, receipt, purchaseInvoice, purchaseReturn, payment (exact, case-sensitive); orders, journals, contras, debit and credit notes and other vouchers are refused.\",\n      \"field\": \"voucherType\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e12\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"d1cb87d6-85c3-37f1-7282-700a14fbfe2f"},{"name":"⚠ busy.vouchers.pdf – Sales return PDF","id":"11147b4a-be07-cdb7-46a3-506a660c19ad","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"salesReturn\",\n  \"voucherId\": {{salesReturnVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /api/v1/voucher-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (<code>DocPrinted</code>).</p>\n<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/voucher-pdf</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · ⚠ BUSY marks the voucher printed\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>voucherType</code> · operation <code>busy.vouchers.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.vouchers.pdf</code></strong> with <code>voucherType: \"salesReturn\"</code> — one BUSY <strong>sales return</strong> (BUSY voucher type 3), printed by BUSY as a <strong>Credit Note</strong>, returned as a base64 PDF. Same route, rules, answer and errors as <strong>busy.vouchers.pdf – Sales invoice PDF</strong> (read that request's description); only the type differs.</p>\n<ul>\n<li>Looked up <strong>by <code>voucherId</code></strong> (<code>{{salesReturnVoucherId}}</code>, COMP0002 / 2026 = 27). The 2026-10-18 acceptance audit found that in COMP0002 / 2026 the number <code>1/2026-27</code> is carried by <strong>two</strong> sales returns (27 and 103), so a lookup by <code>voucherNumber</code> <code>1/2026-27</code> is refused with <code>422 BUSY_DATA_INCONSISTENT</code> (several vouchers with the number; none is chosen), as documented. A unique number (<code>{\"voucherNumber\": \"…\"}</code>) still works.</li>\n<li><code>formatName</code>: one of the company's <strong>sales-return</strong> formats (BUSY <code>PrinterReps</code> RepID 9), e.g. <code>STANDARD</code>; a sales-invoice format is refused with <code>404</code> (<code>field: formatName</code>).</li>\n<li><code>fileName</code> starts with <code>SalesReturn-</code>. BUSY marks the printed voucher as printed, as when printing from BUSY.</li>\n<li>Also through the cloud: <code>{{cloudBaseUrl}}/v1/voucher-pdf</code> relays this type (cloud <code>3b13ab1</code>; see Cloud → Voucher PDFs).</li>\n</ul>\n<p><em>Saved examples: \"200 – sales return PDF (synthetic example)\" has a wrong byteLength/sha256 for its made-up base64; delete it in Postman and keep \"200 – sales return PDF (synthetic)\".</em></p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5aa.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","voucher-pdf"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"7dcab5f5-bfc2-2e92-b1b7-637e3fb3a402","name":"200 – sales return PDF (synthetic example)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"salesReturn\",\n  \"voucherId\": {{salesReturnVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/voucher-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (`DocPrinted`).\n\n**Local** · `POST {{baseUrl}}/api/v1/voucher-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ BUSY marks the voucher printed\n**Required:** `companyCode`, `financialYear`, `voucherType` · operation `busy.vouchers.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.vouchers.pdf`** with `voucherType: \"salesReturn\"` — one BUSY **sales return** (BUSY voucher type 3), printed by BUSY as a **Credit Note**, returned as a base64 PDF. Same route, rules, answer and errors as **busy.vouchers.pdf – Sales invoice PDF** (read that request's description); only the type differs.\n\n- Looked up **by `voucherId`** (`{{salesReturnVoucherId}}`, COMP0002 / 2026 = 27). The 2026-10-18 acceptance audit found that in COMP0002 / 2026 the number `1/2026-27` is carried by **two** sales returns (27 and 103), so a lookup by `voucherNumber` `1/2026-27` is refused with `422 BUSY_DATA_INCONSISTENT` (several vouchers with the number; none is chosen), as documented. A unique number (`{\"voucherNumber\": \"…\"}`) still works.\n- `formatName`: one of the company's **sales-return** formats (BUSY `PrinterReps` RepID 9), e.g. `STANDARD`; a sales-invoice format is refused with `404` (`field: formatName`).\n- `fileName` starts with `SalesReturn-`. BUSY marks the printed voucher as printed, as when printing from BUSY.\n- Also through the cloud: `{{cloudBaseUrl}}/v1/voucher-pdf` relays this type (cloud `3b13ab1`; see Cloud → Voucher PDFs).\n\n_Saved examples: \"200 – sales return PDF (synthetic example)\" has a wrong byteLength/sha256 for its made-up base64; delete it in Postman and keep \"200 – sales return PDF (synthetic)\"._\n\nCanonical contract: `docs/LOCAL-API.md` section 5aa."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e21"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"fileName\": \"SalesReturn-COMP0001-2025-SYN-C-0002.pdf\",\n    \"mimeType\": \"application/pdf\",\n    \"byteLength\": 52,\n    \"sha256\": \"2f0e6f1b2c1c7c5a7b9a3f0e4d5c6b7a8f9e0d1c2b3a4f5e6d7c8b9a0f1e2d3c\",\n    \"pages\": 1,\n    \"contentBase64\": \"JVBERi0xLjQKJSBzeW50aGV0aWMgZXhhbXBsZSwgbm90IGEgcmVhbCBkb2N1bWVudAolJUVPRgo=\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.vouchers.pdf\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e21\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2025\",\n    \"voucherType\": \"salesReturn\",\n    \"lookup\": \"voucherNumber\",\n    \"voucherId\": 97562,\n    \"voucherNumber\": \"SYN/C/0002\",\n    \"voucherDate\": \"2025-06-11\",\n    \"formatSource\": \"busyDefault\",\n    \"formatName\": null,\n    \"elapsedMs\": 4926,\n    \"executedAt\": \"2026-09-26T10:00:00+00:00\"\n  }\n}"},{"id":"0038d9a9-0729-5f23-38be-c865bad79dae","name":"200 – sales return PDF (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"salesReturn\",\n  \"voucherId\": {{salesReturnVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/voucher-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (`DocPrinted`).\n\n**Local** · `POST {{baseUrl}}/api/v1/voucher-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ BUSY marks the voucher printed\n**Required:** `companyCode`, `financialYear`, `voucherType` · operation `busy.vouchers.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.vouchers.pdf`** with `voucherType: \"salesReturn\"` — one BUSY **sales return** (BUSY voucher type 3), printed by BUSY as a **Credit Note**, returned as a base64 PDF. Same route, rules, answer and errors as **busy.vouchers.pdf – Sales invoice PDF** (read that request's description); only the type differs.\n\n- Looked up **by `voucherId`** (`{{salesReturnVoucherId}}`, COMP0002 / 2026 = 27). The 2026-10-18 acceptance audit found that in COMP0002 / 2026 the number `1/2026-27` is carried by **two** sales returns (27 and 103), so a lookup by `voucherNumber` `1/2026-27` is refused with `422 BUSY_DATA_INCONSISTENT` (several vouchers with the number; none is chosen), as documented. A unique number (`{\"voucherNumber\": \"…\"}`) still works.\n- `formatName`: one of the company's **sales-return** formats (BUSY `PrinterReps` RepID 9), e.g. `STANDARD`; a sales-invoice format is refused with `404` (`field: formatName`).\n- `fileName` starts with `SalesReturn-`. BUSY marks the printed voucher as printed, as when printing from BUSY.\n- Also through the cloud: `{{cloudBaseUrl}}/v1/voucher-pdf` relays this type (cloud `3b13ab1`; see Cloud → Voucher PDFs).\n\n_Saved examples: \"200 – sales return PDF (synthetic example)\" has a wrong byteLength/sha256 for its made-up base64; delete it in Postman and keep \"200 – sales return PDF (synthetic)\"._\n\nCanonical contract: `docs/LOCAL-API.md` section 5aa."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e21","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"fileName\": \"SalesReturn-COMP0001-2025-SYN-C-0002.pdf\",\n    \"mimeType\": \"application/pdf\",\n    \"byteLength\": 56,\n    \"sha256\": \"da52e6adee9adc41aca09b8aeebf63fe991b7b4756d728b2dd17240420893568\",\n    \"pages\": 1,\n    \"contentBase64\": \"JVBERi0xLjQKJSBzeW50aGV0aWMgZXhhbXBsZSwgbm90IGEgcmVhbCBkb2N1bWVudAolJUVPRgo=\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.vouchers.pdf\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e21\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2025\",\n    \"voucherType\": \"salesReturn\",\n    \"lookup\": \"voucherNumber\",\n    \"voucherId\": 97562,\n    \"voucherNumber\": \"SYN/C/0002\",\n    \"voucherDate\": \"2025-06-11\",\n    \"formatSource\": \"busyDefault\",\n    \"formatName\": null,\n    \"elapsedMs\": 4926,\n    \"executedAt\": \"2026-09-26T10:00:00+00:00\"\n  }\n}"}],"_postman_id":"11147b4a-be07-cdb7-46a3-506a660c19ad"},{"name":"⚠ busy.vouchers.pdf – Receipt PDF","id":"caec5f80-69e9-b554-5404-76ab2fde32a8","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"receipt\",\n  \"voucherId\": {{receiptVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /api/v1/voucher-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (<code>DocPrinted</code>).</p>\n<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/voucher-pdf</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · ⚠ BUSY marks the voucher printed\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>voucherType</code> · operation <code>busy.vouchers.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.vouchers.pdf</code></strong> with <code>voucherType: \"receipt\"</code> — one BUSY <strong>receipt</strong> (BUSY voucher type 14), printed by BUSY as a <strong>Receipt</strong> (party, amount, amount in words), returned as a base64 PDF. Same route, rules, answer and errors as <strong>busy.vouchers.pdf – Sales invoice PDF</strong> (read that request's description); only the type differs.</p>\n<ul>\n<li>Looked up <strong>by voucher code among receipts only</strong> (<code>receiptVoucherId</code>, COMP0002 voucher 3, number <code>1</code>; a debit note there also has number <code>1</code>, and a sale's code is <code>404</code> here).</li>\n<li><code>formatName</code>: one of the company's <strong>receipt</strong> formats (BUSY <code>PrinterReps</code> RepID 3), e.g. <code>STANDARD</code>. Without it, BUSY prints its STANDARD receipt; a company with no STANDARD receipt format answers <code>409 BUSY_PRINT_FORMAT_MISSING</code>.</li>\n<li><code>fileName</code> starts with <code>Receipt-</code>; a receipt PDF is about 24 KB. BUSY marks the printed receipt as printed, as when printing from BUSY.</li>\n<li>Also through the cloud: <code>{{cloudBaseUrl}}/v1/voucher-pdf</code> relays this type (cloud <code>3b13ab1</code>; see Cloud → Voucher PDFs).</li>\n</ul>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5aa.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","voucher-pdf"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"51da3450-104c-fbbc-343b-3dce907ecc17","name":"200 – receipt PDF (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"receipt\",\n  \"voucherId\": {{receiptVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/voucher-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (`DocPrinted`).\n\n**Local** · `POST {{baseUrl}}/api/v1/voucher-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ BUSY marks the voucher printed\n**Required:** `companyCode`, `financialYear`, `voucherType` · operation `busy.vouchers.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.vouchers.pdf`** with `voucherType: \"receipt\"` — one BUSY **receipt** (BUSY voucher type 14), printed by BUSY as a **Receipt** (party, amount, amount in words), returned as a base64 PDF. Same route, rules, answer and errors as **busy.vouchers.pdf – Sales invoice PDF** (read that request's description); only the type differs.\n\n- Looked up **by voucher code among receipts only** (`receiptVoucherId`, COMP0002 voucher 3, number `1`; a debit note there also has number `1`, and a sale's code is `404` here).\n- `formatName`: one of the company's **receipt** formats (BUSY `PrinterReps` RepID 3), e.g. `STANDARD`. Without it, BUSY prints its STANDARD receipt; a company with no STANDARD receipt format answers `409 BUSY_PRINT_FORMAT_MISSING`.\n- `fileName` starts with `Receipt-`; a receipt PDF is about 24 KB. BUSY marks the printed receipt as printed, as when printing from BUSY.\n- Also through the cloud: `{{cloudBaseUrl}}/v1/voucher-pdf` relays this type (cloud `3b13ab1`; see Cloud → Voucher PDFs).\n\nCanonical contract: `docs/LOCAL-API.md` section 5aa."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e31"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"fileName\": \"Receipt-COMP0001-2025-SYN-R-0003.pdf\",\n    \"mimeType\": \"application/pdf\",\n    \"byteLength\": 56,\n    \"sha256\": \"da52e6adee9adc41aca09b8aeebf63fe991b7b4756d728b2dd17240420893568\",\n    \"pages\": 1,\n    \"contentBase64\": \"JVBERi0xLjQKJSBzeW50aGV0aWMgZXhhbXBsZSwgbm90IGEgcmVhbCBkb2N1bWVudAolJUVPRgo=\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.vouchers.pdf\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e31\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2025\",\n    \"voucherType\": \"receipt\",\n    \"lookup\": \"voucherId\",\n    \"voucherId\": 97563,\n    \"voucherNumber\": \"SYN/R/0003\",\n    \"voucherDate\": \"2025-06-04\",\n    \"formatSource\": \"busyDefault\",\n    \"formatName\": null,\n    \"elapsedMs\": 4210,\n    \"executedAt\": \"2026-09-26T10:00:00+00:00\"\n  }\n}"},{"id":"055bf617-e14e-8e00-bfc0-d34ff563f19e","name":"409 – no STANDARD receipt format in BUSY","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"receipt\",\n  \"voucherId\": {{receiptVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/voucher-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (`DocPrinted`).\n\n**Local** · `POST {{baseUrl}}/api/v1/voucher-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ BUSY marks the voucher printed\n**Required:** `companyCode`, `financialYear`, `voucherType` · operation `busy.vouchers.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.vouchers.pdf`** with `voucherType: \"receipt\"` — one BUSY **receipt** (BUSY voucher type 14), printed by BUSY as a **Receipt** (party, amount, amount in words), returned as a base64 PDF. Same route, rules, answer and errors as **busy.vouchers.pdf – Sales invoice PDF** (read that request's description); only the type differs.\n\n- Looked up **by voucher code among receipts only** (`receiptVoucherId`, COMP0002 voucher 3, number `1`; a debit note there also has number `1`, and a sale's code is `404` here).\n- `formatName`: one of the company's **receipt** formats (BUSY `PrinterReps` RepID 3), e.g. `STANDARD`. Without it, BUSY prints its STANDARD receipt; a company with no STANDARD receipt format answers `409 BUSY_PRINT_FORMAT_MISSING`.\n- `fileName` starts with `Receipt-`; a receipt PDF is about 24 KB. BUSY marks the printed receipt as printed, as when printing from BUSY.\n- Also through the cloud: `{{cloudBaseUrl}}/v1/voucher-pdf` relays this type (cloud `3b13ab1`; see Cloud → Voucher PDFs).\n\nCanonical contract: `docs/LOCAL-API.md` section 5aa."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e32"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_PRINT_FORMAT_MISSING\",\n      \"message\": \"This company has no STANDARD receipt print format in BUSY, so BUSY would create one in the company database while printing, which AI Zeny does not allow. Set up the STANDARD receipt format in BUSY, or send formatName with one of the company's receipt formats.\",\n      \"field\": \"formatName\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e32\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"b42676c9-40a5-3040-16c6-eadad8aad32b","name":"404 – that code is not a receipt","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"receipt\",\n  \"voucherId\": {{receiptVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/voucher-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (`DocPrinted`).\n\n**Local** · `POST {{baseUrl}}/api/v1/voucher-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ BUSY marks the voucher printed\n**Required:** `companyCode`, `financialYear`, `voucherType` · operation `busy.vouchers.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.vouchers.pdf`** with `voucherType: \"receipt\"` — one BUSY **receipt** (BUSY voucher type 14), printed by BUSY as a **Receipt** (party, amount, amount in words), returned as a base64 PDF. Same route, rules, answer and errors as **busy.vouchers.pdf – Sales invoice PDF** (read that request's description); only the type differs.\n\n- Looked up **by voucher code among receipts only** (`receiptVoucherId`, COMP0002 voucher 3, number `1`; a debit note there also has number `1`, and a sale's code is `404` here).\n- `formatName`: one of the company's **receipt** formats (BUSY `PrinterReps` RepID 3), e.g. `STANDARD`. Without it, BUSY prints its STANDARD receipt; a company with no STANDARD receipt format answers `409 BUSY_PRINT_FORMAT_MISSING`.\n- `fileName` starts with `Receipt-`; a receipt PDF is about 24 KB. BUSY marks the printed receipt as printed, as when printing from BUSY.\n- Also through the cloud: `{{cloudBaseUrl}}/v1/voucher-pdf` relays this type (cloud `3b13ab1`; see Cloud → Voucher PDFs).\n\nCanonical contract: `docs/LOCAL-API.md` section 5aa."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e33","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"NOT_FOUND\",\n      \"message\": \"No receipt with that voucherId exists in this company and financial year.\",\n      \"field\": \"voucherId\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e33\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"caec5f80-69e9-b554-5404-76ab2fde32a8"},{"name":"⚠ busy.vouchers.pdf – Purchase invoice PDF","id":"41ca0f9d-a083-a985-9bbb-0c586b1fb716","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"purchaseInvoice\",\n  \"voucherNumber\": \"{{purchaseInvoiceNumber}}\",\n  \"formatName\": \"{{voucherPdfFormat}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /api/v1/voucher-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (<code>DocPrinted</code>).</p>\n<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/voucher-pdf</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · ⚠ BUSY marks the voucher printed\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>voucherType</code> · operation <code>busy.vouchers.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.vouchers.pdf</code></strong> with <code>voucherType: \"purchaseInvoice\"</code> — one BUSY <strong>purchase</strong> voucher (BUSY voucher type 2), printed by BUSY as a <strong>Tax Invoice</strong> with the supplier's details, returned as a base64 PDF. Same route, rules, answer and errors as <strong>busy.vouchers.pdf – Sales invoice PDF</strong> (read that request's description); only the type differs.</p>\n<ul>\n<li>Looked up <strong>by number among purchases only</strong> (<code>purchaseInvoiceNumber</code>, COMP0002 voucher 10, number <code>Q123</code>), with a <strong>named format</strong> (<code>voucherPdfFormat</code> = <code>STANDARD</code>).</li>\n<li><code>formatName</code>: one of the company's <strong>purchase-invoice</strong> formats (BUSY <code>PrinterReps</code> RepID 2). A format of another voucher type is refused with <code>404</code> (<code>field: formatName</code>) — BUSY itself would quietly print its default instead.</li>\n<li><code>fileName</code> starts with <code>PurchaseInvoice-</code>. BUSY marks the printed voucher as printed, as when printing from BUSY.</li>\n<li>Also through the cloud: <code>{{cloudBaseUrl}}/v1/voucher-pdf</code> relays this type (cloud <code>3b13ab1</code>; see Cloud → Voucher PDFs).</li>\n</ul>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5aa.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","voucher-pdf"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"a11d4728-4050-122c-3617-3ec160bc3836","name":"200 – purchase invoice PDF, named format (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"purchaseInvoice\",\n  \"voucherNumber\": \"{{purchaseInvoiceNumber}}\",\n  \"formatName\": \"{{voucherPdfFormat}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/voucher-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (`DocPrinted`).\n\n**Local** · `POST {{baseUrl}}/api/v1/voucher-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ BUSY marks the voucher printed\n**Required:** `companyCode`, `financialYear`, `voucherType` · operation `busy.vouchers.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.vouchers.pdf`** with `voucherType: \"purchaseInvoice\"` — one BUSY **purchase** voucher (BUSY voucher type 2), printed by BUSY as a **Tax Invoice** with the supplier's details, returned as a base64 PDF. Same route, rules, answer and errors as **busy.vouchers.pdf – Sales invoice PDF** (read that request's description); only the type differs.\n\n- Looked up **by number among purchases only** (`purchaseInvoiceNumber`, COMP0002 voucher 10, number `Q123`), with a **named format** (`voucherPdfFormat` = `STANDARD`).\n- `formatName`: one of the company's **purchase-invoice** formats (BUSY `PrinterReps` RepID 2). A format of another voucher type is refused with `404` (`field: formatName`) — BUSY itself would quietly print its default instead.\n- `fileName` starts with `PurchaseInvoice-`. BUSY marks the printed voucher as printed, as when printing from BUSY.\n- Also through the cloud: `{{cloudBaseUrl}}/v1/voucher-pdf` relays this type (cloud `3b13ab1`; see Cloud → Voucher PDFs).\n\nCanonical contract: `docs/LOCAL-API.md` section 5aa."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e41","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"fileName\": \"PurchaseInvoice-COMP0001-2025-SYN-P-0005.pdf\",\n    \"mimeType\": \"application/pdf\",\n    \"byteLength\": 56,\n    \"sha256\": \"da52e6adee9adc41aca09b8aeebf63fe991b7b4756d728b2dd17240420893568\",\n    \"pages\": 1,\n    \"contentBase64\": \"JVBERi0xLjQKJSBzeW50aGV0aWMgZXhhbXBsZSwgbm90IGEgcmVhbCBkb2N1bWVudAolJUVPRgo=\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.vouchers.pdf\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e41\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2025\",\n    \"voucherType\": \"purchaseInvoice\",\n    \"lookup\": \"voucherNumber\",\n    \"voucherId\": 97565,\n    \"voucherNumber\": \"SYN/P/0005\",\n    \"voucherDate\": \"2025-06-06\",\n    \"formatSource\": \"selected\",\n    \"formatName\": \"STANDARD\",\n    \"elapsedMs\": 7825,\n    \"executedAt\": \"2026-09-26T10:00:00+00:00\"\n  }\n}"},{"id":"7603b9b7-2e8c-3c8e-6b21-05ed3267a132","name":"404 – a format of another voucher type","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"purchaseInvoice\",\n  \"voucherNumber\": \"{{purchaseInvoiceNumber}}\",\n  \"formatName\": \"{{voucherPdfFormat}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/voucher-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (`DocPrinted`).\n\n**Local** · `POST {{baseUrl}}/api/v1/voucher-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ BUSY marks the voucher printed\n**Required:** `companyCode`, `financialYear`, `voucherType` · operation `busy.vouchers.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.vouchers.pdf`** with `voucherType: \"purchaseInvoice\"` — one BUSY **purchase** voucher (BUSY voucher type 2), printed by BUSY as a **Tax Invoice** with the supplier's details, returned as a base64 PDF. Same route, rules, answer and errors as **busy.vouchers.pdf – Sales invoice PDF** (read that request's description); only the type differs.\n\n- Looked up **by number among purchases only** (`purchaseInvoiceNumber`, COMP0002 voucher 10, number `Q123`), with a **named format** (`voucherPdfFormat` = `STANDARD`).\n- `formatName`: one of the company's **purchase-invoice** formats (BUSY `PrinterReps` RepID 2). A format of another voucher type is refused with `404` (`field: formatName`) — BUSY itself would quietly print its default instead.\n- `fileName` starts with `PurchaseInvoice-`. BUSY marks the printed voucher as printed, as when printing from BUSY.\n- Also through the cloud: `{{cloudBaseUrl}}/v1/voucher-pdf` relays this type (cloud `3b13ab1`; see Cloud → Voucher PDFs).\n\nCanonical contract: `docs/LOCAL-API.md` section 5aa."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e42"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"NOT_FOUND\",\n      \"message\": \"No purchase-invoice print format of this company in BUSY has exactly that formatName (names are case-sensitive). Leave formatName out for BUSY's default. Available: A5 Purchase; STANDARD.\",\n      \"field\": \"formatName\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e42\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"41ca0f9d-a083-a985-9bbb-0c586b1fb716"},{"name":"⚠ busy.vouchers.pdf – Purchase return PDF","id":"407ae6a3-782d-245f-97ef-a0d7ff4bcb70","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"purchaseReturn\",\n  \"voucherId\": {{purchaseReturnVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /api/v1/voucher-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (<code>DocPrinted</code>).</p>\n<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/voucher-pdf</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · ⚠ BUSY marks the voucher printed\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>voucherType</code> · operation <code>busy.vouchers.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.vouchers.pdf</code></strong> with <code>voucherType: \"purchaseReturn\"</code> — one BUSY <strong>purchase return</strong> (BUSY voucher type 10), printed by BUSY as a <strong>Debit Note</strong>, returned as a base64 PDF. Same route, rules, answer and errors as <strong>busy.vouchers.pdf – Sales invoice PDF</strong> (read that request's description); only the type differs.</p>\n<ul>\n<li>Looked up <strong>by voucher code among purchase returns only</strong> (<code>purchaseReturnVoucherId</code>, COMP0002 voucher 29, number <code>12</code>). A BUSY <em>debit note</em> voucher (type 17) is a different type and is not printed here.</li>\n<li><code>formatName</code>: one of the company's <strong>purchase-return</strong> formats (BUSY <code>PrinterReps</code> RepID 10), e.g. <code>STANDARD</code>.</li>\n<li><code>fileName</code> starts with <code>PurchaseReturn-</code>. BUSY marks the printed voucher as printed, as when printing from BUSY.</li>\n<li>Also through the cloud: <code>{{cloudBaseUrl}}/v1/voucher-pdf</code> relays this type (cloud <code>3b13ab1</code>; see Cloud → Voucher PDFs).</li>\n</ul>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5aa.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","voucher-pdf"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"11d42f3d-f6bd-feda-8c15-0a4b791d73e2","name":"200 – purchase return PDF (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"purchaseReturn\",\n  \"voucherId\": {{purchaseReturnVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/voucher-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (`DocPrinted`).\n\n**Local** · `POST {{baseUrl}}/api/v1/voucher-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ BUSY marks the voucher printed\n**Required:** `companyCode`, `financialYear`, `voucherType` · operation `busy.vouchers.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.vouchers.pdf`** with `voucherType: \"purchaseReturn\"` — one BUSY **purchase return** (BUSY voucher type 10), printed by BUSY as a **Debit Note**, returned as a base64 PDF. Same route, rules, answer and errors as **busy.vouchers.pdf – Sales invoice PDF** (read that request's description); only the type differs.\n\n- Looked up **by voucher code among purchase returns only** (`purchaseReturnVoucherId`, COMP0002 voucher 29, number `12`). A BUSY *debit note* voucher (type 17) is a different type and is not printed here.\n- `formatName`: one of the company's **purchase-return** formats (BUSY `PrinterReps` RepID 10), e.g. `STANDARD`.\n- `fileName` starts with `PurchaseReturn-`. BUSY marks the printed voucher as printed, as when printing from BUSY.\n- Also through the cloud: `{{cloudBaseUrl}}/v1/voucher-pdf` relays this type (cloud `3b13ab1`; see Cloud → Voucher PDFs).\n\nCanonical contract: `docs/LOCAL-API.md` section 5aa."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e51","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"fileName\": \"PurchaseReturn-COMP0001-2025-SYN-D-0006.pdf\",\n    \"mimeType\": \"application/pdf\",\n    \"byteLength\": 56,\n    \"sha256\": \"da52e6adee9adc41aca09b8aeebf63fe991b7b4756d728b2dd17240420893568\",\n    \"pages\": 1,\n    \"contentBase64\": \"JVBERi0xLjQKJSBzeW50aGV0aWMgZXhhbXBsZSwgbm90IGEgcmVhbCBkb2N1bWVudAolJUVPRgo=\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.vouchers.pdf\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e51\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2025\",\n    \"voucherType\": \"purchaseReturn\",\n    \"lookup\": \"voucherId\",\n    \"voucherId\": 97566,\n    \"voucherNumber\": \"SYN/D/0006\",\n    \"voucherDate\": \"2025-06-07\",\n    \"formatSource\": \"busyDefault\",\n    \"formatName\": null,\n    \"elapsedMs\": 5898,\n    \"executedAt\": \"2026-09-26T10:00:00+00:00\"\n  }\n}"}],"_postman_id":"407ae6a3-782d-245f-97ef-a0d7ff4bcb70"},{"name":"⚠ busy.vouchers.pdf – Payment PDF","id":"6b149375-f5be-ad9f-13ae-06fd959292a3","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"payment\",\n  \"voucherId\": {{paymentVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /api/v1/voucher-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (<code>DocPrinted</code>).</p>\n<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/voucher-pdf</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · ⚠ BUSY marks the voucher printed\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>voucherType</code> · operation <code>busy.vouchers.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.vouchers.pdf</code></strong> with <code>voucherType: \"payment\"</code> — one BUSY <strong>payment</strong> (BUSY voucher type 19), printed by BUSY as a <strong>Payment Advice</strong> (party, amount, amount in words), returned as a base64 PDF. Same route, rules, answer and errors as <strong>busy.vouchers.pdf – Sales invoice PDF</strong> (read that request's description); only the type differs.</p>\n<ul>\n<li>Looked up <strong>by voucher code among payments only</strong> (<code>paymentVoucherId</code>, COMP0002 voucher 22, number <code>P09</code>).</li>\n<li><code>formatName</code>: one of the company's <strong>payment</strong> formats (BUSY <code>PrinterReps</code> RepID 12), e.g. <code>STANDARD</code>.</li>\n<li><code>fileName</code> starts with <code>Payment-</code>; a payment PDF is about 25 KB. BUSY marks the printed voucher as printed, as when printing from BUSY.</li>\n<li>Also through the cloud: <code>{{cloudBaseUrl}}/v1/voucher-pdf</code> relays this type (cloud <code>3b13ab1</code>; see Cloud → Voucher PDFs).</li>\n</ul>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5aa.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","voucher-pdf"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"4ab1e076-1c0c-fa2c-2f47-4b845fc66063","name":"200 – payment PDF (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"payment\",\n  \"voucherId\": {{paymentVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/voucher-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/voucher-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (`DocPrinted`).\n\n**Local** · `POST {{baseUrl}}/api/v1/voucher-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ BUSY marks the voucher printed\n**Required:** `companyCode`, `financialYear`, `voucherType` · operation `busy.vouchers.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.vouchers.pdf`** with `voucherType: \"payment\"` — one BUSY **payment** (BUSY voucher type 19), printed by BUSY as a **Payment Advice** (party, amount, amount in words), returned as a base64 PDF. Same route, rules, answer and errors as **busy.vouchers.pdf – Sales invoice PDF** (read that request's description); only the type differs.\n\n- Looked up **by voucher code among payments only** (`paymentVoucherId`, COMP0002 voucher 22, number `P09`).\n- `formatName`: one of the company's **payment** formats (BUSY `PrinterReps` RepID 12), e.g. `STANDARD`.\n- `fileName` starts with `Payment-`; a payment PDF is about 25 KB. BUSY marks the printed voucher as printed, as when printing from BUSY.\n- Also through the cloud: `{{cloudBaseUrl}}/v1/voucher-pdf` relays this type (cloud `3b13ab1`; see Cloud → Voucher PDFs).\n\nCanonical contract: `docs/LOCAL-API.md` section 5aa."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e61","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"fileName\": \"Payment-COMP0001-2025-SYN-PY-0007.pdf\",\n    \"mimeType\": \"application/pdf\",\n    \"byteLength\": 56,\n    \"sha256\": \"da52e6adee9adc41aca09b8aeebf63fe991b7b4756d728b2dd17240420893568\",\n    \"pages\": 1,\n    \"contentBase64\": \"JVBERi0xLjQKJSBzeW50aGV0aWMgZXhhbXBsZSwgbm90IGEgcmVhbCBkb2N1bWVudAolJUVPRgo=\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.vouchers.pdf\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e61\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2025\",\n    \"voucherType\": \"payment\",\n    \"lookup\": \"voucherId\",\n    \"voucherId\": 97567,\n    \"voucherNumber\": \"SYN/PY/0007\",\n    \"voucherDate\": \"2025-06-08\",\n    \"formatSource\": \"busyDefault\",\n    \"formatName\": null,\n    \"elapsedMs\": 4042,\n    \"executedAt\": \"2026-09-26T10:00:00+00:00\"\n  }\n}"}],"_postman_id":"6b149375-f5be-ad9f-13ae-06fd959292a3"}],"id":"00dabc42-9da6-40ea-95df-ec634ddfd391","description":"<p>Printing an existing voucher through BUSY returns a PDF and marks that voucher printed (DocPrinted). Explicit one-send confirmation is required on each request. Accounting amounts are not changed by the proven print-flag effect.</p>\n","_postman_id":"00dabc42-9da6-40ea-95df-ec634ddfd391","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Custom SQL, Saved Queries & Scripts (read only)","item":[{"name":"busy.custom-sql.execute – Execute custom SQL","id":"b4bc692c-3308-2f92-eddc-2c7c148d2a49","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"query\": \"SELECT M.MasterType AS master_type, COUNT(*) AS masters FROM Master1 AS M WHERE M.MasterType = @masterType GROUP BY M.MasterType ORDER BY M.MasterType\",\n  \"parameters\": { \"masterType\": 6 },\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/execute-custom-sql","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/execute-custom-sql</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>query</code> · operation <code>busy.custom-sql.execute</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.custom-sql.execute</code></strong> (BusyNotify <code>POST /v1/execute-custom-sql</code>). One page of <strong>your own read-only SELECT</strong> on the selected company and financial year, run directly on BUSY's SQL Server database or Access file. <strong>Read only.</strong></p>\n<p>Request: <code>{ companyCode, financialYear, query, parameters?, page?, pageSize? }</code>.</p>\n<ul>\n<li><code>query</code> — one <code>SELECT</code> (SQL Server may start with one <code>WITH</code> list), at most 8000 characters, in the SQL of the company's database type: nothing is translated between SQL Server and Access.</li>\n<li>Refused before BUSY is reached (<code>400 CUSTOM_SQL_REJECTED</code>, field <code>query</code>, the text is never repeated): comments, a second or stacked statement, anything that writes, changes schema, settings, permissions or transactions, runs procedures, waits or takes write locks, system databases/catalogs/functions, <code>@@</code> variables, temporary tables, names of three or more parts, <code>OPENROWSET</code>/<code>OPENQUERY</code>/<code>OPENDATASOURCE</code>, Access <code>IN</code> clauses and paths or connection strings in names, ODBC escapes. <code>\"…\"</code> is a quoted <strong>name</strong> on both providers; text literals use single quotes. Access text literals may not contain <code>?</code>, braces or <code>;</code>.</li>\n<li><code>parameters</code> — one member per <code>@name</code> placeholder and no others (names compared without case): text (≤ 1000), a number, <code>true</code>/<code>false</code> or <code>null</code>. Bound as parameters, never written into the text. Send dates as text and convert them in the query. On Access a non-integer number is bound as a double.</li>\n<li><code>page</code> from 1, <code>pageSize</code> 1–500 (default 100); <code>page × pageSize</code> ≤ 100 000. Each page runs the query again: add <code>ORDER BY</code> for stable pages.</li>\n</ul>\n<p>The query runs read only (Access <code>ReadOnly=1</code>; SQL Server in the selected year database inside a transaction that is always rolled back), through the one-read-at-a-time BUSY gate, 60 s statement / 120 s call bound; a client that disconnects cancels it.</p>\n<p>Response (200): <code>data = { columns: [{ name, type }], rows: [[…], …] }</code> — one array per row in column order, so a repeated column name never overwrites another. Types: <code>boolean</code> (Access Yes = true), <code>integer</code>, <code>decimal</code>, <code>number</code>, <code>text</code> (as stored), <code>date</code>, <code>time</code>, <code>datetime</code> (<code>yyyy-MM-ddTHH:mm:ss[.fraction]</code>), <code>datetimeoffset</code>, <code>binary</code> (Base64), <code>guid</code>. <code>metadata</code>: <code>apiVersion</code>, <code>operation</code>, <code>requestId</code>, <code>companyCode</code>, <code>financialYear</code>, <code>provider</code>, <code>queryFingerprint</code> (one-way, structure only), <code>parameterCount</code>, <code>page</code>, <code>pageSize</code>, <code>returnedRowCount</code>, <code>columnCount</code>, <code>hasMore</code>, <code>elapsedMs</code>, <code>executedAt</code>. Never the query text, a parameter value or a provider message.</p>\n<p>Errors: <code>400 INVALID_PARAMETER</code> / <code>CUSTOM_SQL_REJECTED</code> / <code>BAD_REQUEST</code> (unknown members such as <code>authToken</code>, <code>sqlQueryBase64</code>, <code>tables</code>, <code>params</code>), <code>403 FINANCIAL_YEAR_NOT_ALLOWED</code>, <code>404 COMPANY_NOT_CONFIGURED</code>, <code>409 COMPANY_DISABLED</code>, <code>422 CUSTOM_SQL_FAILED</code> (BUSY could not run it, or no result set), <code>422 RESULT_TOO_LARGE</code> (&gt; 256 columns, a value &gt; 32 768 characters, a page &gt; 4 000 000 characters), <code>422 UNSUPPORTED_VALUE</code>, <code>503</code>, <code>504 BUSY_TIMEOUT</code>.</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5q.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","execute-custom-sql"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"6d9adc8d-7034-7c2e-9492-dfccda46d449","name":"200 – one aggregate row (synthetic, Access)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"query\": \"SELECT M.MasterType AS master_type, COUNT(*) AS masters FROM Master1 AS M WHERE M.MasterType = @masterType GROUP BY M.MasterType ORDER BY M.MasterType\",\n  \"parameters\": { \"masterType\": 6 },\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/execute-custom-sql","description":"**Local** · `POST {{baseUrl}}/api/v1/execute-custom-sql` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear`, `query` · operation `busy.custom-sql.execute`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.custom-sql.execute`** (BusyNotify `POST /v1/execute-custom-sql`). One page of **your own read-only SELECT** on the selected company and financial year, run directly on BUSY's SQL Server database or Access file. **Read only.**\n\nRequest: `{ companyCode, financialYear, query, parameters?, page?, pageSize? }`.\n- `query` — one `SELECT` (SQL Server may start with one `WITH` list), at most 8000 characters, in the SQL of the company's database type: nothing is translated between SQL Server and Access.\n- Refused before BUSY is reached (`400 CUSTOM_SQL_REJECTED`, field `query`, the text is never repeated): comments, a second or stacked statement, anything that writes, changes schema, settings, permissions or transactions, runs procedures, waits or takes write locks, system databases/catalogs/functions, `@@` variables, temporary tables, names of three or more parts, `OPENROWSET`/`OPENQUERY`/`OPENDATASOURCE`, Access `IN` clauses and paths or connection strings in names, ODBC escapes. `\"…\"` is a quoted **name** on both providers; text literals use single quotes. Access text literals may not contain `?`, braces or `;`.\n- `parameters` — one member per `@name` placeholder and no others (names compared without case): text (≤ 1000), a number, `true`/`false` or `null`. Bound as parameters, never written into the text. Send dates as text and convert them in the query. On Access a non-integer number is bound as a double.\n- `page` from 1, `pageSize` 1–500 (default 100); `page × pageSize` ≤ 100 000. Each page runs the query again: add `ORDER BY` for stable pages.\n\nThe query runs read only (Access `ReadOnly=1`; SQL Server in the selected year database inside a transaction that is always rolled back), through the one-read-at-a-time BUSY gate, 60 s statement / 120 s call bound; a client that disconnects cancels it.\n\nResponse (200): `data = { columns: [{ name, type }], rows: [[…], …] }` — one array per row in column order, so a repeated column name never overwrites another. Types: `boolean` (Access Yes = true), `integer`, `decimal`, `number`, `text` (as stored), `date`, `time`, `datetime` (`yyyy-MM-ddTHH:mm:ss[.fraction]`), `datetimeoffset`, `binary` (Base64), `guid`. `metadata`: `apiVersion`, `operation`, `requestId`, `companyCode`, `financialYear`, `provider`, `queryFingerprint` (one-way, structure only), `parameterCount`, `page`, `pageSize`, `returnedRowCount`, `columnCount`, `hasMore`, `elapsedMs`, `executedAt`. Never the query text, a parameter value or a provider message.\n\nErrors: `400 INVALID_PARAMETER` / `CUSTOM_SQL_REJECTED` / `BAD_REQUEST` (unknown members such as `authToken`, `sqlQueryBase64`, `tables`, `params`), `403 FINANCIAL_YEAR_NOT_ALLOWED`, `404 COMPANY_NOT_CONFIGURED`, `409 COMPANY_DISABLED`, `422 CUSTOM_SQL_FAILED` (BUSY could not run it, or no result set), `422 RESULT_TOO_LARGE` (> 256 columns, a value > 32 768 characters, a page > 4 000 000 characters), `422 UNSUPPORTED_VALUE`, `503`, `504 BUSY_TIMEOUT`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5q."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"columns\": [\n      { \"name\": \"master_type\", \"type\": \"integer\" },\n      { \"name\": \"masters\", \"type\": \"integer\" }\n    ],\n    \"rows\": [\n      [6, 21]\n    ]\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.custom-sql.execute\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2025\",\n    \"provider\": \"access\",\n    \"queryFingerprint\": \"6f49a5039c66f143\",\n    \"parameterCount\": 1,\n    \"page\": 1,\n    \"pageSize\": 100,\n    \"returnedRowCount\": 1,\n    \"columnCount\": 2,\n    \"hasMore\": false,\n    \"elapsedMs\": 35,\n    \"executedAt\": \"2026-09-26T10:00:00+00:00\"\n  }\n}"},{"id":"24f65ef0-d093-c2db-a486-e8278ed6c6a5","name":"400 – CUSTOM_SQL_REJECTED (a second statement)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"query\": \"SELECT M.MasterType AS master_type, COUNT(*) AS masters FROM Master1 AS M WHERE M.MasterType = @masterType GROUP BY M.MasterType ORDER BY M.MasterType\",\n  \"parameters\": { \"masterType\": 6 },\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/execute-custom-sql","description":"**Local** · `POST {{baseUrl}}/api/v1/execute-custom-sql` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear`, `query` · operation `busy.custom-sql.execute`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.custom-sql.execute`** (BusyNotify `POST /v1/execute-custom-sql`). One page of **your own read-only SELECT** on the selected company and financial year, run directly on BUSY's SQL Server database or Access file. **Read only.**\n\nRequest: `{ companyCode, financialYear, query, parameters?, page?, pageSize? }`.\n- `query` — one `SELECT` (SQL Server may start with one `WITH` list), at most 8000 characters, in the SQL of the company's database type: nothing is translated between SQL Server and Access.\n- Refused before BUSY is reached (`400 CUSTOM_SQL_REJECTED`, field `query`, the text is never repeated): comments, a second or stacked statement, anything that writes, changes schema, settings, permissions or transactions, runs procedures, waits or takes write locks, system databases/catalogs/functions, `@@` variables, temporary tables, names of three or more parts, `OPENROWSET`/`OPENQUERY`/`OPENDATASOURCE`, Access `IN` clauses and paths or connection strings in names, ODBC escapes. `\"…\"` is a quoted **name** on both providers; text literals use single quotes. Access text literals may not contain `?`, braces or `;`.\n- `parameters` — one member per `@name` placeholder and no others (names compared without case): text (≤ 1000), a number, `true`/`false` or `null`. Bound as parameters, never written into the text. Send dates as text and convert them in the query. On Access a non-integer number is bound as a double.\n- `page` from 1, `pageSize` 1–500 (default 100); `page × pageSize` ≤ 100 000. Each page runs the query again: add `ORDER BY` for stable pages.\n\nThe query runs read only (Access `ReadOnly=1`; SQL Server in the selected year database inside a transaction that is always rolled back), through the one-read-at-a-time BUSY gate, 60 s statement / 120 s call bound; a client that disconnects cancels it.\n\nResponse (200): `data = { columns: [{ name, type }], rows: [[…], …] }` — one array per row in column order, so a repeated column name never overwrites another. Types: `boolean` (Access Yes = true), `integer`, `decimal`, `number`, `text` (as stored), `date`, `time`, `datetime` (`yyyy-MM-ddTHH:mm:ss[.fraction]`), `datetimeoffset`, `binary` (Base64), `guid`. `metadata`: `apiVersion`, `operation`, `requestId`, `companyCode`, `financialYear`, `provider`, `queryFingerprint` (one-way, structure only), `parameterCount`, `page`, `pageSize`, `returnedRowCount`, `columnCount`, `hasMore`, `elapsedMs`, `executedAt`. Never the query text, a parameter value or a provider message.\n\nErrors: `400 INVALID_PARAMETER` / `CUSTOM_SQL_REJECTED` / `BAD_REQUEST` (unknown members such as `authToken`, `sqlQueryBase64`, `tables`, `params`), `403 FINANCIAL_YEAR_NOT_ALLOWED`, `404 COMPANY_NOT_CONFIGURED`, `409 COMPANY_DISABLED`, `422 CUSTOM_SQL_FAILED` (BUSY could not run it, or no result set), `422 RESULT_TOO_LARGE` (> 256 columns, a value > 32 768 characters, a page > 4 000 000 characters), `422 UNSUPPORTED_VALUE`, `503`, `504 BUSY_TIMEOUT`.\n\nCanonical contract: `docs/LOCAL-API.md` section 5q."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"CUSTOM_SQL_REJECTED\",\n      \"message\": \"query must be exactly one read-only SELECT statement (SQL Server may start with one WITH list); a second statement is not allowed.\",\n      \"field\": \"query\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"b4bc692c-3308-2f92-eddc-2c7c148d2a49"},{"name":"busy.custom-sql.execute – a write is refused before BUSY (expects 400)","id":"de9622d4-9dee-61d1-86ff-8c8ec7ffa249","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"query\": \"SELECT 1 AS one; UPDATE Master1 SET Name = 'x' WHERE 1 = 0\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/execute-custom-sql","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/execute-custom-sql</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>query</code> · operation <code>busy.custom-sql.execute</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Negative check for custom SQL</strong> — safe to run: the stacked <code>UPDATE</code> is refused by AI Zeny's read-only boundary <strong>before BUSY is reached</strong> (nothing is executed; it would change nothing anyway, <code>WHERE 1 = 0</code>). Expects <code>400 CUSTOM_SQL_REJECTED</code> with <code>field: \"query\"</code> and a fixed message that never repeats the query. See the main <em>Execute custom SQL</em> request and <code>docs/LOCAL-API.md</code> section 5q for everything that is refused.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","execute-custom-sql"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"de9622d4-9dee-61d1-86ff-8c8ec7ffa249"},{"name":"busy.custom-query.execute – Execute custom query","id":"118f13ed-a46a-3db8-77cb-d8f281aa14d3","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"queryName\": \"stock_status_with_mc_name\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/execute-custom-query","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/execute-custom-query</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>queryName</code> · operation <code>busy.custom-query.execute</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong><code>busy.custom-query.execute</code></strong> (BusyNotify <code>POST /v1/execute-custom-query</code>). One page of a report from AI Zeny's <strong>local named-query registry</strong>. <strong>Read only. Product and stock data.</strong></p>\n<p>The reference kept saved queries in its cloud (encrypted SQL per user, Redis) plus two built-in reports in code. AI Zeny has no cloud query store: only the two built-in reports exist, compiled in, each with separate SQL Server and Access statements. The name only selects a registry entry; it never chooses a file, a class or SQL text. Any other name is <code>404 NOT_FOUND</code> (field <code>queryName</code>).</p>\n<p>Request: <code>{ companyCode, financialYear, queryName, parameters?, page?, pageSize? }</code>.</p>\n<ul>\n<li><code>queryName</code> — <code>stock_aging_fifo</code>, or <code>stock_status_with_mc_name</code> (also accepted: <code>stock_status_with_mc</code>, <code>stock_status_mc_name</code>, <code>stock_status_mc_wise</code>, <code>stock_status_mc</code>, <code>stock_status_with_material_center</code>); trimmed, case ignored; <code>metadata.queryName</code> is the canonical name.</li>\n<li><code>parameters</code> — only <code>branchId</code> (a branch code as a number, or a branch code, name or alias as text; limits both reports to the material centres used by that branch's voucher series) and, for <code>stock_aging_fifo</code>, <code>asOnDate</code> (<code>YYYY-MM-DD</code> inside the year; default today in UTC, refused when today is outside the year). The reference's <code>branch_id</code> is refused.</li>\n<li><code>page</code> from 1, <code>pageSize</code> 1–500 (default 100).</li>\n</ul>\n<p>Reports: <code>stock_aging_fifo</code> — per product the remaining stock after FIFO issues (sales returns restore the last issued lots; a return with nothing issued is aged from 1 April; issues without stock wait for later receipts), in 0–15, 16–30, 31–60, 61–90 and 91+ day buckets, quantities and values; only movements on or before <code>asOnDate</code> count (a stated correction). <code>stock_status_with_mc_name</code> — every product with codes, description, MRP, group, stock, unit, price (latest purchase price, else opening price, else the product's D4), value, brand, product id, then one column per material centre (a repeated name gets <code> (code)</code>).</p>\n<p>Response (200): <code>data = { columns: [{ name, type }], rows: [[…], …] }</code>, as <code>execute-custom-sql</code>. <code>metadata</code>: <code>apiVersion</code>, <code>operation</code>, <code>requestId</code>, <code>companyCode</code>, <code>financialYear</code>, <code>provider</code>, <code>queryName</code>, <code>page</code>, <code>pageSize</code>, <code>returnedRowCount</code>, <code>columnCount</code>, <code>hasMore</code>, <code>elapsedMs</code>, <code>executedAt</code> (never a parameter value).</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5q.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","execute-custom-query"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"cc7dafbc-57be-f5bd-7300-5d629a700a3a","name":"200 – stock status, one product in two material centres (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"queryName\": \"stock_status_with_mc_name\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/execute-custom-query","description":"**Local** · `POST {{baseUrl}}/api/v1/execute-custom-query` · Bearer `{{localApiToken}}` (collection auth) · Read only — does not write to BUSY\n**Required:** `companyCode`, `financialYear`, `queryName` · operation `busy.custom-query.execute`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**`busy.custom-query.execute`** (BusyNotify `POST /v1/execute-custom-query`). One page of a report from AI Zeny's **local named-query registry**. **Read only. Product and stock data.**\n\nThe reference kept saved queries in its cloud (encrypted SQL per user, Redis) plus two built-in reports in code. AI Zeny has no cloud query store: only the two built-in reports exist, compiled in, each with separate SQL Server and Access statements. The name only selects a registry entry; it never chooses a file, a class or SQL text. Any other name is `404 NOT_FOUND` (field `queryName`).\n\nRequest: `{ companyCode, financialYear, queryName, parameters?, page?, pageSize? }`.\n- `queryName` — `stock_aging_fifo`, or `stock_status_with_mc_name` (also accepted: `stock_status_with_mc`, `stock_status_mc_name`, `stock_status_mc_wise`, `stock_status_mc`, `stock_status_with_material_center`); trimmed, case ignored; `metadata.queryName` is the canonical name.\n- `parameters` — only `branchId` (a branch code as a number, or a branch code, name or alias as text; limits both reports to the material centres used by that branch's voucher series) and, for `stock_aging_fifo`, `asOnDate` (`YYYY-MM-DD` inside the year; default today in UTC, refused when today is outside the year). The reference's `branch_id` is refused.\n- `page` from 1, `pageSize` 1–500 (default 100).\n\nReports: `stock_aging_fifo` — per product the remaining stock after FIFO issues (sales returns restore the last issued lots; a return with nothing issued is aged from 1 April; issues without stock wait for later receipts), in 0–15, 16–30, 31–60, 61–90 and 91+ day buckets, quantities and values; only movements on or before `asOnDate` count (a stated correction). `stock_status_with_mc_name` — every product with codes, description, MRP, group, stock, unit, price (latest purchase price, else opening price, else the product's D4), value, brand, product id, then one column per material centre (a repeated name gets ` (code)`).\n\nResponse (200): `data = { columns: [{ name, type }], rows: [[…], …] }`, as `execute-custom-sql`. `metadata`: `apiVersion`, `operation`, `requestId`, `companyCode`, `financialYear`, `provider`, `queryName`, `page`, `pageSize`, `returnedRowCount`, `columnCount`, `hasMore`, `elapsedMs`, `executedAt` (never a parameter value).\n\nCanonical contract: `docs/LOCAL-API.md` section 5q."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"columns\": [\n      { \"name\": \"item_code\", \"type\": \"text\" }, { \"name\": \"item_code_1\", \"type\": \"text\" }, { \"name\": \"item_code_2\", \"type\": \"text\" },\n      { \"name\": \"item_name\", \"type\": \"text\" }, { \"name\": \"description\", \"type\": \"text\" }, { \"name\": \"sku_classification\", \"type\": \"text\" },\n      { \"name\": \"mrp\", \"type\": \"number\" }, { \"name\": \"group_name\", \"type\": \"text\" }, { \"name\": \"stock_qty\", \"type\": \"number\" },\n      { \"name\": \"unit\", \"type\": \"text\" }, { \"name\": \"price\", \"type\": \"number\" }, { \"name\": \"total_amount\", \"type\": \"number\" },\n      { \"name\": \"brand\", \"type\": \"text\" }, { \"name\": \"product_id\", \"type\": \"integer\" },\n      { \"name\": \"Synthetic Godown\", \"type\": \"number\" }, { \"name\": \"Synthetic Store\", \"type\": \"number\" }\n    ],\n    \"rows\": [\n      [\"SW-1\", \"SW-ALT\", null, \"Synthetic Widget\", \"Synthetic description\", \"A\", 150, \"Synthetic Group\", 13, \"Pcs\", 90, 1170, \"Synthetic Brand\", 6001, 5, 8]\n    ]\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.custom-query.execute\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2025\",\n    \"provider\": \"access\",\n    \"queryName\": \"stock_status_with_mc_name\",\n    \"page\": 1,\n    \"pageSize\": 100,\n    \"returnedRowCount\": 1,\n    \"columnCount\": 16,\n    \"hasMore\": false,\n    \"elapsedMs\": 48,\n    \"executedAt\": \"2026-09-26T10:00:00+00:00\"\n  }\n}"}],"_postman_id":"118f13ed-a46a-3db8-77cb-d8f281aa14d3"},{"name":"List saved queries","id":"cffb7cba-bed1-424b-ce14-c4ce2d63f4c9","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/saved-queries","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/busy/saved-queries</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>Every saved query by name: <code>{ name, sqlServer, access, parameters, revision, createdUtc, updatedUtc }</code> (no SQL text). <code>metadata: { count }</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","saved-queries"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"cffb7cba-bed1-424b-ce14-c4ce2d63f4c9"},{"name":"View one saved query","id":"d65ae358-4d21-be70-07be-296730c33efd","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}</code> · Bearer token · Read only — does not write to BUSY</p>\n<p>One saved query by name: its definitions, parameters and revision. A query protected by its own source PIN answers <code>403 SAVED_QUERY_PIN_REQUIRED</code> here; use <strong>Open one saved query</strong> with the PIN.</p>\n<p><strong>Needs <code>savedQueryName</code>.</strong> When it is empty or only spaces, the request skips itself and says so in the console: without a name the URL would be the list route <code>/api/v1/busy/saved-queries/</code>, which answers 200 and would pass for the wrong reason. The test also checks that a 200 answer is the one query asked for, not the list.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","saved-queries","{{savedQueryName}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"d65ae358-4d21-be70-07be-296730c33efd"},{"name":"Preview a draft (not saved)","id":"afd32bd0-327b-4c53-0671-6a982623915a","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"query\": {\n    \"sqlServerQuery\": \"SELECT MasterType, COUNT(*) AS n FROM Master1 WHERE MasterType >= @minType GROUP BY MasterType ORDER BY MasterType\",\n    \"accessQuery\": \"SELECT MasterType, COUNT(*) AS n FROM Master1 WHERE MasterType >= @minType GROUP BY MasterType ORDER BY MasterType\",\n    \"parameters\": [ { \"name\": \"minType\", \"type\": \"integer\", \"required\": true } ]\n  },\n  \"parameters\": { \"minType\": 2 },\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/saved-queries/preview","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/saved-queries/preview</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>Runs an unsaved draft once on one company and year: the save rules, the company's own provider definition, the declared parameters, the read-only reader. Answers like <code>/execute-custom-sql</code> (operation <code>busy.saved-query.preview</code>). Nothing is stored. A refusal names <code>query.sqlServerQuery</code>, <code>query.accessQuery</code> or <code>query.parameters</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","saved-queries","preview"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"afd32bd0-327b-4c53-0671-6a982623915a"},{"name":"Run a saved query by name","id":"8c417c23-1fe3-d965-e22f-c8c3f5969157","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"queryName\": \"{{savedQueryName}}\",\n  \"parameters\": { \"fromCode\": 1 },\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/execute-custom-query","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/execute-custom-query</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>queryName</code> · operation <code>busy.custom-query.execute</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>Runs the saved query <code>{{savedQueryName}}</code> (built-in report names are looked up first and answer as before). <code>parameters</code> holds one value per declared parameter of its declared type; a required one must be present and not null; an optional one that is missing binds NULL.</p>\n<p>Answer: <code>data: { columns: [ { name, type } ], rows: [ [ … ] ] }</code> (positional, repeated names kept, NULLs, exact decimals and 64-bit integers); <code>metadata</code> as <code>execute-custom-query</code> with <code>querySource: \"saved\"</code>.</p>\n<p>Errors: <code>400 INVALID_PARAMETER</code> (field <code>parameters</code>), <code>404 NOT_FOUND</code> (field <code>queryName</code>), <code>409 SAVED_QUERY_PROVIDER_MISSING</code>, <code>409 SAVED_QUERY_INVALID</code>, <code>422 CUSTOM_SQL_FAILED</code> / <code>RESULT_TOO_LARGE</code> / <code>UNSUPPORTED_VALUE</code>, and the company and year refusals.</p>\n<p><strong>Test scenarios:</strong> This normal saved-query request requires HTTP 200, <code>success: true</code>, result columns/rows and <code>querySource: saved</code>. To test a documented refusal deliberately, set the current variable <code>expectedSavedQueryErrorCode</code> to the exact expected error code for that separate scenario; the test then requires a 4xx/5xx envelope with that exact code. Clear it for the normal success case. No request is sent by this change.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","execute-custom-query"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"8c417c23-1fe3-d965-e22f-c8c3f5969157"},{"name":"List scripts","id":"c7819c08-bca2-3b69-8844-a6422ad6f93c","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/scripts","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/busy/scripts</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>Every script by name: <code>{ name, kind, enabled, allowHttp, assignments, check, revision, createdUtc, updatedUtc }</code> (no source). <code>metadata: { count }</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","scripts"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"c7819c08-bca2-3b69-8844-a6422ad6f93c"},{"name":"View one script","id":"4928ac58-7916-77f3-001d-3c0c7ea61226","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/scripts/{{scriptName}}","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/busy/scripts/{{scriptName}}</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>One script with its source, assignments, check and revision. The name rule is applied (case and spaces do not matter). <code>404 SCRIPT_NOT_FOUND</code> when none. Stores the revision in <code>scriptRevision</code> for an edit or delete.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","scripts","{{scriptName}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"4928ac58-7916-77f3-001d-3c0c7ea61226"},{"name":"Test a draft transform (not saved)","id":"47cc0cf3-6903-8cb4-a818-1b861760c100","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"script\": {\n    \"kind\": \"transform\",\n    \"source\": \"function main(input) {\\n  console.log('rows', input.data.length);\\n  return { count: input.data.length, names: input.data.map(r => r.mc_name) };\\n}\"\n  },\n  \"operation\": \"/material-centers\",\n  \"request\": {}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/scripts/preview","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/scripts/preview</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Preview reads BUSY and runs an unsaved draft; it does not save the script.\n<strong>Answer:</strong> <code>{ success, data, metadata }</code>; source failures use <code>success:false,data:null,metadata.error</code>.</p>\n<p>The body example is a safe transform: <code>companyCode</code>, <code>financialYear</code>, <code>script:{kind:'transform',source}</code> and <code>operation</code> plus optional object <code>request</code>. For a named draft, use <code>kind:'named'</code> and optional object <code>parameters</code> instead. A transform's source read happens before the script. The result is <code>data:{source:{data,metadata}|null,result:{ok,data,error},console}</code>. HTTP 200 means a test report, <strong>not</strong> script success; check <code>result.ok</code>.</p>\n<p>FL-18 preview policy: messaging <code>get/list/summary</code>, read-only API/query calls and transforms are allowed. Message insert/update/claim/state transitions/cancel and external <code>http.request</code> are refused before any effect, even if draft <code>allowHttp:true</code>; nested scripts and API calls carry the same rule. The script failure appears in the 200 report, for example <code>{\"success\":true,\"data\":{\"source\":null,\"result\":{\"ok\":false,\"data\":null,\"error\":{\"code\":\"SCRIPT_PREVIEW_EFFECT_REFUSED\",\"message\":\"Preview scripts may read and transform data, but cannot change messaging rows, run effectful API operations, or make external HTTP requests.\",\"line\":null,\"column\":null}},\"console\":[]},\"metadata\":{\"operation\":\"busy.script.preview\"}}</code> (illustrative partial metadata). Normal non-preview runs retain their existing permissions. This preview can read real BUSY data; it never contacts an external HTTP endpoint through the script helper.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> §5s.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","scripts","preview"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"47cc0cf3-6903-8cb4-a818-1b861760c100"},{"name":"Run a named script","id":"27227aae-7dd2-cc7b-9a29-741d3c7af459","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"scriptName\": \"{{scriptName}}\",\n  \"parameters\": { \"minAmount\": 1000 }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/execute-script","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/execute-script</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only towards BUSY (runs a saved script; it reads through the PC's operations and calls the internet only if the script allows it)\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>scriptName</code> · operation <code>busy.script.execute</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>Runs the named script <code>{{scriptName}}</code> (enabled, assigned to the company). <code>parameters</code> is handed to the script as <code>input.parameters</code>, numbers exact. Answer: <code>data</code> = what the script returns (an object or array); <code>metadata = { apiVersion, operation: busy.script.execute, requestId, companyCode, financialYear, script { name, revision }, calls, httpRequests, elapsedMs, executedAt }</code>.</p>\n<p>Errors: <code>404 SCRIPT_NOT_FOUND</code>, <code>409 SCRIPT_NOT_ASSIGNED</code> / <code>SCRIPT_DISABLED</code> (field <code>scriptName</code>), <code>422 SCRIPT_FAILED</code> (message with the script line), <code>SCRIPT_OUTPUT_INVALID</code>, <code>SCRIPT_OUTPUT_TOO_LARGE</code>, <code>SCRIPT_LIMIT_EXCEEDED</code>, <code>SCRIPT_RECURSION</code>, <code>403 SCRIPT_SCOPE_DENIED</code>, <code>504 SCRIPT_TIMEOUT</code>, and the company and year refusals.</p>\n<p>Also through the cloud: <code>{{cloudBaseUrl}}/v1/execute-script</code> (cloud <code>3b13ab1</code>; see Cloud → Custom SQL, Named Reports &amp; Scripts), with the same checks and limits on the PC. The cloud sends it to the PC once and never retries it; send an <code>Idempotency-Key</code> header to have a repeat refused (<code>409</code>) instead of run again.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","execute-script"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"27227aae-7dd2-cc7b-9a29-741d3c7af459"},{"name":"Standard API with a transform variant","id":"34f6678f-68dd-a2ff-f8e4-ae1e0f811055","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"script\": \"{{scriptName}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-centers","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/material-centers</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.material-centers.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>Any synchronous V1 route (not the stream, not execute-script) accepts one extra member, <code>\"script\": \"&lt;name&gt;\"</code>: the response-transform variant (or default) assigned to this company and route. The operation runs first; its failure is the answer and no script runs. Then the named script transforms <code>data</code>; <code>metadata</code> stays the operation's own plus <code>metadata.script { name, revision, selectedBy: \"request\", calls, httpRequests, elapsedMs }</code>. An unknown, disabled or unassigned name is <code>404 SCRIPT_NOT_FOUND</code> / <code>409 SCRIPT_DISABLED</code> / <code>409 SCRIPT_NOT_ASSIGNED</code> (field <code>script</code>) — never another script or the untransformed data. Without <code>script</code>, the company's enabled default (if any) applies.</p>\n<p>Also through the cloud: since cloud <code>3b13ab1</code> every synchronous Cloud BUSY route accepts the same <code>script</code> member and the PC applies the transform (not the credit-line stream, <code>/execute-script</code>, <code>/voucher-pdf</code> or the writes — the same exceptions as on the Local API).</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","material-centers"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"34f6678f-68dd-a2ff-f8e4-ae1e0f811055"},{"name":"Open one saved query (SQL; the query's PIN when protected)","id":"fb822c93-8ad9-de1e-6e67-4ae921c2f974","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"pin\": \"{{savedQueryPin}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}/open","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}/open</code> · Bearer token · Read only — shows a saved query's SQL, changes nothing</p>\n<p>Opens one saved query with its SQL: the one route that returns a protected query's source, and only with that query's own PIN (<code>savedQueryPin</code>, not the PC's M-PIN). A query without a PIN opens with an empty body. A refusal never carries SQL.</p>\n<p><strong>Needs <code>savedQueryName</code>.</strong> When it is missing, empty or only spaces, the request skips itself and says so in the console instead of sending <code>/api/v1/busy/saved-queries//open</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","saved-queries","{{savedQueryName}}","open"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"3f470726-e0c2-6962-eeaa-18f0d90717fc","name":"200 – a protected query opened with its PIN (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"pin\": \"{{savedQueryPin}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}/open","description":"**Local** · `POST {{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}/open` · Bearer token · Read only — shows a saved query's SQL, changes nothing\n\nOpens one saved query with its SQL: the one route that returns a protected query's source, and only with that query's own PIN (`savedQueryPin`, not the PC's M-PIN). A query without a PIN opens with an empty body. A refusal never carries SQL.\n\n**Needs `savedQueryName`.** When it is missing, empty or only spaces, the request skips itself and says so in the console instead of sending `/api/v1/busy/saved-queries//open`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"name\": \"Margins\",\n    \"sqlServerQuery\": \"SELECT Code, Name FROM Master1 WHERE MasterType = 6 AND Code >= @fromCode ORDER BY Code\",\n    \"accessQuery\": \"SELECT Code, Name FROM Master1 WHERE MasterType = 6 AND Code >= @fromCode ORDER BY Code\",\n    \"parameters\": [ { \"name\": \"fromCode\", \"type\": \"integer\", \"required\": true } ],\n    \"revision\": 3,\n    \"createdUtc\": \"2026-10-16T09:00:00+00:00\",\n    \"updatedUtc\": \"2026-10-16T09:30:00+00:00\",\n    \"protected\": true\n  },\n  \"metadata\": {}\n}"},{"id":"cf88d06b-37ae-7a5b-a209-c1974411b6b1","name":"403 – wrong PIN: no SQL (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"pin\": \"{{savedQueryPin}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}/open","description":"**Local** · `POST {{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}/open` · Bearer token · Read only — shows a saved query's SQL, changes nothing\n\nOpens one saved query with its SQL: the one route that returns a protected query's source, and only with that query's own PIN (`savedQueryPin`, not the PC's M-PIN). A query without a PIN opens with an empty body. A refusal never carries SQL.\n\n**Needs `savedQueryName`.** When it is missing, empty or only spaces, the request skips itself and says so in the console instead of sending `/api/v1/busy/saved-queries//open`."},"status":"Forbidden","code":403,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": { \"code\": \"SAVED_QUERY_PIN_INCORRECT\", \"message\": \"That is not this query's PIN. Nothing was shown or changed.\", \"field\": \"pin\" },\n    \"requestId\": \"00000000000000000000000000000000\"\n  }\n}"}],"_postman_id":"fb822c93-8ad9-de1e-6e67-4ae921c2f974"}],"id":"655104d6-5709-4324-a90a-7c6ddb0258f1","description":"<p>Your own read-only SQL, the built-in and saved named queries, and scripts: run, preview and read definitions. Read only towards BUSY. Creating or changing saved queries and scripts is in ⚠ PC Settings &amp; Management. These are POST requests only because they carry a JSON body; none of them changes BUSY or AI Zeny.</p>\n","_postman_id":"655104d6-5709-4324-a90a-7c6ddb0258f1","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Schedules & Messages (read only)","item":[{"name":"Time zones","id":"258fafb2-702e-416d-4a27-fcfd2c7975a5","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/timezones","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/timezones</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>The one time zone catalogue schedules may use (docs/LOCAL-API.md 5t): Windows zones named by IANA id, legacy names shown current, sorted by offset. <code>offset</code> is the offset <strong>now</strong>, for reading only — a schedule stores the <code>id</code>, never an offset, so a change of the PC's time zone never moves a schedule.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td><code>{ \"success\": true, \"data\": [ { \"id\": \"Asia/Kolkata\", \"name\": \"Chennai, Kolkata, Mumbai, New Delhi\", \"offset\": \"+05:30\", \"observesDaylightSaving\": false }, … ], \"metadata\": { \"defaultTimeZone\": \"Asia/Kolkata\", \"count\": 139 } }</code></td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","timezones"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"258fafb2-702e-416d-4a27-fcfd2c7975a5"},{"name":"List schedules","id":"1a2b330d-ce7f-dd8a-6184-ac9cdada727e","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/schedules","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/busy/schedules</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>Every schedule on this PC (docs/LOCAL-API.md 5t), without parameters: script, company, year, zone, primary and retry times, pause, <code>state</code> (<code>active</code>, <code>pausedToday</code>, <code>paused</code>, <code>needsAttention</code>), <code>nextRunUtc</code> / <code>nextRunLocal</code>, today's <code>window</code> (<code>date</code>, <code>slots</code>, <code>closes</code>), <code>activeRun</code>, <code>latestRun</code>, <code>attention</code>, <code>revision</code>. <code>metadata.scheduler</code> holds the scheduler's counts.</p>\n<p>The <strong>AI Zeny Host</strong> runs schedules itself, with the window closed or locked; nothing calls an execution route at a scheduled time.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td><code>{ \"success\": true, \"data\": [ { \"name\": \"Daily-Summary\", \"scriptName\": \"Debtor-Summary\", \"companyCode\": \"COMP0001\", \"financialYear\": \"2026\", \"timeZone\": \"Asia/Kolkata\", \"primaryTime\": \"09:00\", \"retryTimes\": [\"10:00\",\"11:00\"], \"paused\": { \"permanent\": false, \"dates\": [] }, \"state\": \"active\", \"nextRunUtc\": \"…\", \"nextRunLocal\": \"2026-09-30 09:00\", \"window\": { \"date\": \"2026-09-29\", \"slots\": [\"09:00\",\"10:00\",\"11:00\"], \"closes\": \"11:15\" }, \"activeRun\": null, \"latestRun\": { … }, \"attention\": null, \"revision\": 1, … } ], \"metadata\": { \"count\": 1, \"scheduler\": { … } } }</code></td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","schedules"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"1a2b330d-ce7f-dd8a-6184-ac9cdada727e"},{"name":"Get one schedule","id":"ce35459c-d1cc-12ed-a259-201c514b430f","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/schedules/{{scheduleName}}","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/busy/schedules/{{scheduleName}}</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>One schedule with its <code>parameters</code> (stored encrypted on the PC, returned only here). Set the environment variable <code>scheduleName</code> first.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the schedule, as in the list, plus <code>parameters</code></td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>SCHEDULE_NOT_FOUND</code></td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","schedules","{{scheduleName}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"ce35459c-d1cc-12ed-a259-201c514b430f"},{"name":"Run history","id":"554979e5-c40f-c477-c780-8fead6351059","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/schedule-runs?page=1&pageSize=50&schedule={{scheduleName}}","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/busy/schedule-runs</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>History of runs and closed days, newest first (docs/LOCAL-API.md 5t). Safe metadata only: schedule, script and revision, company, year, zone, <code>trigger</code> (<code>manual</code> = Run now, never part of a day's schedule; <code>primary</code>, <code>retry</code>, <code>catch-up</code>; <code>scheduled</code> = a day closed <code>missed</code> or <code>paused</code> without an attempt), <code>occurrenceDate</code>, <code>slotTime</code>, <code>attempt</code>, <code>status</code>, times, <code>durationMs</code>, <code>startedLocal</code>, <code>errorCode</code>, <code>errorMessage</code>. Never parameters, output or anything the script sent.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td><code>{ \"success\": true, \"data\": [ { \"id\": 12, \"schedule\": \"Daily-Summary\", \"trigger\": \"retry\", \"attempt\": 2, \"status\": \"succeeded\", … } ], \"metadata\": { \"page\": 1, \"pageSize\": 50, \"total\": 12 } }</code></td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>SCHEDULE_INVALID</code> with <code>field</code> (<code>trigger</code>, <code>status</code>, <code>from</code>, <code>page</code>)</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>SCHEDULE_NOT_FOUND</code> (field <code>schedule</code>)</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","schedule-runs"],"host":["{{baseUrl}}"],"query":[{"key":"page","value":"1"},{"description":{"content":"<p>1 to 200</p>\n","type":"text/plain"},"key":"pageSize","value":"50"},{"description":{"content":"<p>optional: one schedule</p>\n","type":"text/plain"},"key":"schedule","value":"{{scheduleName}}"},{"disabled":true,"description":{"content":"<p>optional: manual, primary, retry, catch-up or scheduled (a missed or paused day)</p>\n","type":"text/plain"},"key":"trigger","value":"manual"},{"disabled":true,"description":{"content":"<p>optional: queued, running, succeeded, failed, cancelled, interrupted, missed, paused</p>\n","type":"text/plain"},"key":"status","value":"failed"},{"disabled":true,"description":{"content":"<p>optional ISO 8601 instant with offset</p>\n","type":"text/plain"},"key":"from","value":"2026-09-29T00:00:00Z"},{"disabled":true,"description":{"content":"<p>optional ISO 8601 instant with offset</p>\n","type":"text/plain"},"key":"to","value":"2026-09-30T00:00:00Z"}],"variable":[]}},"response":[],"_postman_id":"554979e5-c40f-c477-c780-8fead6351059"},{"name":"Get one run","id":"aae36be3-2abb-0a4d-cad8-82e6416615f6","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/schedule-runs/{{scheduleRunId}}","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/busy/schedule-runs/{{scheduleRunId}}</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>One history row by id (<code>scheduleRunId</code> is set by <em>Run history</em> from its newest row, or by <em>Run now</em>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the run</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>SCHEDULE_RUN_NOT_FOUND</code></td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","schedule-runs","{{scheduleRunId}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"aae36be3-2abb-0a4d-cad8-82e6416615f6"},{"name":"List messages","id":"61c18a96-1f04-bf0f-6c4f-f50d17c636a5","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/messages/email?page=1&pageSize=50","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/messages/email</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>A page of rows, newest first (docs/LOCAL-API.md 5u). Filters as the script <code>messages.&lt;channel&gt;.list(filter)</code>; unknown query members are refused.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td><code>{ \"success\": true, \"data\": [ { \"id\": 12, \"status\": \"sent\", \"revision\": 3, \"createdUtc\": \"…\", \"companyCode\": \"COMP0001\", \"recipientId\": \"ACC-1\", … } ], \"metadata\": { \"page\": 1, \"pageSize\": 50, \"total\": 12, \"filters\": { … } } }</code></td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>MESSAGE_INVALID</code> with <code>field</code></td>\n</tr>\n<tr>\n<td>404</td>\n<td>an unknown channel</td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","messages","email"],"host":["{{baseUrl}}"],"query":[{"key":"page","value":"1"},{"description":{"content":"<p>1 to 200</p>\n","type":"text/plain"},"key":"pageSize","value":"50"},{"disabled":true,"description":{"content":"<p>optional: pending, processing, sent, delivered, read, failed, cancelled, uncertain (repeatable or comma-separated)</p>\n","type":"text/plain"},"key":"status","value":"uncertain"},{"disabled":true,"description":{"content":"<p>optional</p>\n","type":"text/plain"},"key":"companyCode","value":"{{companyCode}}"},{"disabled":true,"description":{"content":"<p>optional</p>\n","type":"text/plain"},"key":"scriptName","value":""},{"disabled":true,"description":{"content":"<p>optional</p>\n","type":"text/plain"},"key":"batchId","value":""},{"disabled":true,"description":{"content":"<p>optional</p>\n","type":"text/plain"},"key":"correlationId","value":""},{"disabled":true,"description":{"content":"<p>optional: recipient id, name, address or phone, exact</p>\n","type":"text/plain"},"key":"recipient","value":""},{"disabled":true,"description":{"content":"<p>optional</p>\n","type":"text/plain"},"key":"idempotencyKey","value":""},{"disabled":true,"description":{"content":"<p>optional ISO 8601 instant, createdUtc from (inclusive)</p>\n","type":"text/plain"},"key":"from","value":"2026-09-29T00:00:00Z"},{"disabled":true,"description":{"content":"<p>optional ISO 8601 instant, createdUtc to (exclusive)</p>\n","type":"text/plain"},"key":"to","value":"2026-09-30T00:00:00Z"}],"variable":[]}},"response":[],"_postman_id":"61c18a96-1f04-bf0f-6c4f-f50d17c636a5"},{"name":"Message counts by status","id":"c5970ac7-7e58-9998-6132-c8530ea2caa2","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/messages/email/summary","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/messages/email/summary</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><code>data</code> = <code>{ total, byStatus }</code>. <code>total</code> applies every filter; <code>byStatus</code> applies every filter except <code>status</code>, so each status's count is always shown.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td><code>{ \"success\": true, \"data\": { \"total\": 25, \"byStatus\": { \"pending\": 0, \"processing\": 0, \"sent\": 24, \"delivered\": 0, \"read\": 0, \"failed\": 1, \"cancelled\": 0, \"uncertain\": 0 } }, \"metadata\": { \"filters\": { } } }</code></td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","messages","email","summary"],"host":["{{baseUrl}}"],"query":[{"disabled":true,"description":{"content":"<p>optional; every list filter except paging is accepted</p>\n","type":"text/plain"},"key":"companyCode","value":"{{companyCode}}"}],"variable":[]}},"response":[],"_postman_id":"c5970ac7-7e58-9998-6132-c8530ea2caa2"},{"name":"Get one message","id":"1aaa8bfc-ea0f-32d2-220b-290b6ec761e1","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/messages/email/{{messageId}}","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/messages/email/{{messageId}}</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · Read only — does not write to BUSY\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p>One row with its <code>attempts</code> and <code>events</code> (the newest 500, with <code>eventCount</code>). An <code>uncertain</code> row means a send began and its outcome was never recorded: AI Zeny never sends it again or marks it sent by itself; reconcile it after checking with the provider.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the row, <code>attempts</code>, <code>events</code></td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>MESSAGE_NOT_FOUND</code></td>\n</tr>\n</tbody>\n</table>\n</div>","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","messages","email","{{messageId}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"1aaa8bfc-ea0f-32d2-220b-290b6ec761e1"}],"id":"610cfd47-7cd9-48e3-b034-d7279bbd9ef6","description":"<p>Script schedules, their run history, the time-zone catalogue, and the Email/WhatsApp history scripts recorded. Read only; local only (never through the cloud).</p>\n","_postman_id":"610cfd47-7cd9-48e3-b034-d7279bbd9ef6","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ Master Create & Modify — WRITES TO BUSY","item":[{"name":"⚠ BUSY master – create account (writes to BUSY)","id":"e1632973-b0d3-c1d8-a51c-72991e1139f6","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Account 01\",\n  \"alias\": \"AZAPI-ACC-01\",\n  \"parentGroup\": { \"name\": \"Sundry Debtors\" },\n  \"address\": {\n    \"line1\": \"1 Example Road\",\n    \"state\": { \"name\": \"Delhi\" },\n    \"pinCode\": \"110001\",\n    \"mobile\": \"9000000000\",\n    \"email\": \"accounts@example.invalid\"\n  },\n  \"gstRegistrationType\": \"unregistered\",\n  \"creditDays\": 15,\n  \"creditLimit\": 25000\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-create","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/account-create</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>)\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>name</code>, <code>parentGroup</code> · operation <code>busy.accounts.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books. Run manually, one at a time.</strong> <code>busy.accounts.create</code> (<code>POST /api/v1/account-create</code>) creates one BUSY account (ledger) through BUSY's own COM component on this PC, then reads it back from BUSY and checks every field you sent before answering. <strong>SQL Server companies with a SQL login, or Access companies</strong>. Never an upsert. Not relayed by the current Windows build (the cloud route exists since cloud <code>3b13ab1</code>, but this PC refuses relayed writes: see Cloud → ⚠ Master Create &amp; Modify); never run from scripts.</p>\n<p><strong>Safe test guidance</strong></p>\n<ul>\n<li>Use only a <strong>development-test company</strong> (<code>targetCompanyCode</code>, e.g. COMP0002 on the development PC) and a <strong>new, unique test name</strong> (change <code>name</code> and <code>alias</code> before each send). Never a customer's company.</li>\n<li>Nothing is deleted automatically: a created test account stays in BUSY. Remove it in BUSY yourself if needed.</li>\n<li><strong>Never retry a write blindly.</strong> A second send of the same body is refused (<code>409 MASTER_NAME_TAKEN</code>) if the first saved. After <code>504 BUSY_WRITE_UNCERTAIN</code>, read <code>metadata.error.details.reconciliation</code> (<code>found</code> + <code>masterId</code>, <code>notFound</code>, <code>notChecked</code>) and look the account up (Customers) before anything else.</li>\n<li><code>502 BUSY_WRITE_UNVERIFIED</code> means BUSY <strong>did</strong> save but its read-back differs (<code>details.masterId</code>, <code>details.mismatchedFields</code>): check it in BUSY.</li>\n<li>One BUSY job at a time on the PC (shared with voucher PDFs), up to 2 minutes: give the request a long timeout.</li>\n</ul>\n<p><strong>Body:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>name</code> (1-40, required), <code>alias</code>, <code>printName</code> (1-60), <code>parentGroup</code> (required, <code>{\"code\": n}</code> or <code>{\"name\": \"…\"}</code>), <code>address</code> {<code>line1</code>…<code>line4</code>, <code>state</code>, <code>pinCode</code>, <code>station</code>, <code>contactPerson</code>, <code>telephone</code>, <code>mobile</code>, <code>whatsApp</code>, <code>email</code>, <code>gstin</code>, <code>pan</code>}, <code>gstRegistrationType</code> (<code>registered</code> | <code>unregistered</code>), <code>creditDays</code> (0-9999), <code>creditLimit</code> (&gt; 0), <code>openingBalance</code>.</p>\n<p><strong>Opening balance</strong> (part of the books, optional): <code>{ \"amount\": 300, \"type\": \"debit\"|\"credit\", \"allocation\": \"billWise\"|\"unallocated\", \"billReferences\": [ { \"number\": \"OB-0001\", \"date\": \"2026-03-15\", \"dueDate\": \"2026-04-15\", \"amount\": 300, \"type\": \"debit\" } ] }</code>. <code>allocation</code> is required: <code>billWise</code> needs bill references whose signed total equals the balance (dates on or before 1 April of the year, at most 50); <code>unallocated</code> allows none and says so in <code>metadata.openingBalanceAllocation</code>. The example body leaves it out on purpose.</p>\n<p><strong>Answer (200):</strong> <code>data</code> = <code>{ masterId, name, alias, fields }</code> (each field sent, as BUSY stored it; references with the code BUSY resolved); <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, masterType, outcome (created), verifiedFields, [openingBalanceAllocation], elapsedMs, executedAt</code>. The test stores <code>masterAccountId</code> / <code>masterAccountName</code> for the modify request.</p>\n<p><strong>Errors:</strong> 400 <code>BAD_REQUEST</code>, <code>INVALID_PARAMETER</code> (<code>field</code>); 404 <code>COMPANY_NOT_CONFIGURED</code>; 409 <code>MASTER_NAME_TAKEN</code>, <code>MASTER_WRITE_PROVIDER_UNSUPPORTED</code>, <code>COMPANY_DISABLED</code>, <code>FINANCIAL_YEAR_NOT_ALLOWED</code>; 422 <code>MASTER_REFERENCE_NOT_FOUND</code>, <code>MASTER_REFERENCE_AMBIGUOUS</code>; 502 <code>BUSY_WRITE_FAILED</code>, <code>BUSY_WRITE_UNVERIFIED</code>; 503 <code>BUSY_COM_*</code> prerequisites, <code>BUSY_COM_QUEUE_TIMEOUT</code>; 504 <code>BUSY_WRITE_UNCERTAIN</code>, <code>BUSY_COM_TIMEOUT</code>.</p>\n<p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5ab; customer guide <code>docs/public/api/account-and-product-masters.md</code>.</p>\n<p><strong>Optional fields (since 2026-10-17):</strong> optional member <code>optionalFields</code>. Keyed <code>OF1</code>–<code>OF10</code> (read the slots with <strong>busy.optional-fields.definitions</strong> for the same year first); the slot must be defined for this master type in that year (<code>422 OPTIONAL_FIELD_NOT_DEFINED</code>). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Accounts: on <strong>Access companies</strong> also dropdown, whole-number, date and Yes/No fields, with the product rules below (create a new account dropdown value first with <strong>⚠ BUSY account dropdown value – create</strong>); on <strong>SQL Server companies</strong> free-text fields only — the other account kinds are refused with <code>422 OPTIONAL_FIELD_UNSUPPORTED</code> (proven on Access, not yet on SQL Server). On a create, <code>null</code> is refused. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (<code>502 BUSY_WRITE_UNVERIFIED</code> names <code>optionalFields.OF</code>n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract <code>docs/LOCAL-API.md</code> 5an; guide <code>docs/public/api/optional-fields.md</code>.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n<h2 id=\"full-synthetic-optional-field-request-example-local-only\">FULL synthetic optional-field request example (Local only)</h2>\n<p>The raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check <code>/optional-field-definitions</code> before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, <code>null</code> clears OF1; omitted slots remain unchanged. On create, <code>null</code> is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Account 01\",\n  \"alias\": \"AZAPI-ACC-01\",\n  \"parentGroup\": {\n    \"name\": \"Sundry Debtors\"\n  },\n  \"address\": {\n    \"line1\": \"1 Example Road\",\n    \"state\": {\n      \"name\": \"Delhi\"\n    },\n    \"pinCode\": \"110001\",\n    \"mobile\": \"9000000000\",\n    \"email\": \"accounts@example.invalid\"\n  },\n  \"gstRegistrationType\": \"unregistered\",\n  \"creditDays\": 15,\n  \"creditLimit\": 25000,\n  \"optionalFields\": {\n    \"OF1\": \"Synthetic customer class\"\n  }\n}\n</code></pre>\n<p>Original destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","account-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"767afb6e-c39f-6a17-f0f3-91ed2532b279","name":"200 – account created and verified (synthetic example)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Account 01\",\n  \"alias\": \"AZAPI-ACC-01\",\n  \"parentGroup\": { \"name\": \"Sundry Debtors\" },\n  \"address\": {\n    \"line1\": \"1 Example Road\",\n    \"state\": { \"name\": \"Delhi\" },\n    \"pinCode\": \"110001\",\n    \"mobile\": \"9000000000\",\n    \"email\": \"accounts@example.invalid\"\n  },\n  \"gstRegistrationType\": \"unregistered\",\n  \"creditDays\": 15,\n  \"creditLimit\": 25000\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-create","description":"**Local** · `POST {{baseUrl}}/api/v1/account-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `name`, `parentGroup` · operation `busy.accounts.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.accounts.create` (`POST /api/v1/account-create`) creates one BUSY account (ledger) through BUSY's own COM component on this PC, then reads it back from BUSY and checks every field you sent before answering. **SQL Server companies with a SQL login, or Access companies**. Never an upsert. Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Use only a **development-test company** (`targetCompanyCode`, e.g. COMP0002 on the development PC) and a **new, unique test name** (change `name` and `alias` before each send). Never a customer's company.\n- Nothing is deleted automatically: a created test account stays in BUSY. Remove it in BUSY yourself if needed.\n- **Never retry a write blindly.** A second send of the same body is refused (`409 MASTER_NAME_TAKEN`) if the first saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `masterId`, `notFound`, `notChecked`) and look the account up (Customers) before anything else.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back differs (`details.masterId`, `details.mismatchedFields`): check it in BUSY.\n- One BUSY job at a time on the PC (shared with voucher PDFs), up to 2 minutes: give the request a long timeout.\n\n**Body:** `companyCode`, `financialYear`, `name` (1-40, required), `alias`, `printName` (1-60), `parentGroup` (required, `{\"code\": n}` or `{\"name\": \"…\"}`), `address` {`line1`…`line4`, `state`, `pinCode`, `station`, `contactPerson`, `telephone`, `mobile`, `whatsApp`, `email`, `gstin`, `pan`}, `gstRegistrationType` (`registered` | `unregistered`), `creditDays` (0-9999), `creditLimit` (> 0), `openingBalance`.\n\n**Opening balance** (part of the books, optional): `{ \"amount\": 300, \"type\": \"debit\"|\"credit\", \"allocation\": \"billWise\"|\"unallocated\", \"billReferences\": [ { \"number\": \"OB-0001\", \"date\": \"2026-03-15\", \"dueDate\": \"2026-04-15\", \"amount\": 300, \"type\": \"debit\" } ] }`. `allocation` is required: `billWise` needs bill references whose signed total equals the balance (dates on or before 1 April of the year, at most 50); `unallocated` allows none and says so in `metadata.openingBalanceAllocation`. The example body leaves it out on purpose.\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }` (each field sent, as BUSY stored it; references with the code BUSY resolved); `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType, outcome (created), verifiedFields, [openingBalanceAllocation], elapsedMs, executedAt`. The test stores `masterAccountId` / `masterAccountName` for the modify request.\n\n**Errors:** 400 `BAD_REQUEST`, `INVALID_PARAMETER` (`field`); 404 `COMPANY_NOT_CONFIGURED`; 409 `MASTER_NAME_TAKEN`, `MASTER_WRITE_PROVIDER_UNSUPPORTED`, `COMPANY_DISABLED`, `FINANCIAL_YEAR_NOT_ALLOWED`; 422 `MASTER_REFERENCE_NOT_FOUND`, `MASTER_REFERENCE_AMBIGUOUS`; 502 `BUSY_WRITE_FAILED`, `BUSY_WRITE_UNVERIFIED`; 503 `BUSY_COM_*` prerequisites, `BUSY_COM_QUEUE_TIMEOUT`; 504 `BUSY_WRITE_UNCERTAIN`, `BUSY_COM_TIMEOUT`.\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab; customer guide `docs/public/api/account-and-product-masters.md`.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Accounts: on **Access companies** also dropdown, whole-number, date and Yes/No fields, with the product rules below (create a new account dropdown value first with **⚠ BUSY account dropdown value – create**); on **SQL Server companies** free-text fields only — the other account kinds are refused with `422 OPTIONAL_FIELD_UNSUPPORTED` (proven on Access, not yet on SQL Server). On a create, `null` is refused. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\n\n## FULL synthetic optional-field request example (Local only)\nThe raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check `/optional-field-definitions` before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, `null` clears OF1; omitted slots remain unchanged. On create, `null` is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.\n```json\n{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Account 01\",\n  \"alias\": \"AZAPI-ACC-01\",\n  \"parentGroup\": {\n    \"name\": \"Sundry Debtors\"\n  },\n  \"address\": {\n    \"line1\": \"1 Example Road\",\n    \"state\": {\n      \"name\": \"Delhi\"\n    },\n    \"pinCode\": \"110001\",\n    \"mobile\": \"9000000000\",\n    \"email\": \"accounts@example.invalid\"\n  },\n  \"gstRegistrationType\": \"unregistered\",\n  \"creditDays\": 15,\n  \"creditLimit\": 25000,\n  \"optionalFields\": {\n    \"OF1\": \"Synthetic customer class\"\n  }\n}\n```\n\r\n\r\nOriginal destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"masterId\": 7001,\n    \"name\": \"AZAPI Test Account 01\",\n    \"alias\": \"AZAPI-ACC-01\",\n    \"fields\": {\n      \"name\": \"AZAPI Test Account 01\",\n      \"alias\": \"AZAPI-ACC-01\",\n      \"parentGroup\": { \"code\": 116, \"name\": \"Sundry Debtors\" },\n      \"address.line1\": \"1 Example Road\",\n      \"address.state\": { \"code\": 1053, \"name\": \"Delhi\" },\n      \"address.pinCode\": \"110001\",\n      \"address.mobile\": \"9000000000\",\n      \"address.email\": \"accounts@example.invalid\",\n      \"gstRegistrationType\": \"unregistered\",\n      \"creditDays\": 15,\n      \"creditLimit\": 25000\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.accounts.create\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"masterType\": \"account\",\n    \"outcome\": \"created\",\n    \"verifiedFields\": [\"name\", \"alias\", \"parentGroup\", \"address.line1\", \"address.state\", \"address.pinCode\", \"address.mobile\", \"address.email\", \"gstRegistrationType\", \"creditDays\", \"creditLimit\"],\n    \"elapsedMs\": 4210,\n    \"executedAt\": \"2026-09-26T10:00:00+00:00\"\n  }\n}"},{"id":"5ff7c2fa-5fed-07a6-6f3b-8c9226a56096","name":"409 – name already used (MASTER_NAME_TAKEN; nothing written)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Account 01\",\n  \"alias\": \"AZAPI-ACC-01\",\n  \"parentGroup\": { \"name\": \"Sundry Debtors\" },\n  \"address\": {\n    \"line1\": \"1 Example Road\",\n    \"state\": { \"name\": \"Delhi\" },\n    \"pinCode\": \"110001\",\n    \"mobile\": \"9000000000\",\n    \"email\": \"accounts@example.invalid\"\n  },\n  \"gstRegistrationType\": \"unregistered\",\n  \"creditDays\": 15,\n  \"creditLimit\": 25000\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-create","description":"**Local** · `POST {{baseUrl}}/api/v1/account-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `name`, `parentGroup` · operation `busy.accounts.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.accounts.create` (`POST /api/v1/account-create`) creates one BUSY account (ledger) through BUSY's own COM component on this PC, then reads it back from BUSY and checks every field you sent before answering. **SQL Server companies with a SQL login, or Access companies**. Never an upsert. Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Use only a **development-test company** (`targetCompanyCode`, e.g. COMP0002 on the development PC) and a **new, unique test name** (change `name` and `alias` before each send). Never a customer's company.\n- Nothing is deleted automatically: a created test account stays in BUSY. Remove it in BUSY yourself if needed.\n- **Never retry a write blindly.** A second send of the same body is refused (`409 MASTER_NAME_TAKEN`) if the first saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `masterId`, `notFound`, `notChecked`) and look the account up (Customers) before anything else.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back differs (`details.masterId`, `details.mismatchedFields`): check it in BUSY.\n- One BUSY job at a time on the PC (shared with voucher PDFs), up to 2 minutes: give the request a long timeout.\n\n**Body:** `companyCode`, `financialYear`, `name` (1-40, required), `alias`, `printName` (1-60), `parentGroup` (required, `{\"code\": n}` or `{\"name\": \"…\"}`), `address` {`line1`…`line4`, `state`, `pinCode`, `station`, `contactPerson`, `telephone`, `mobile`, `whatsApp`, `email`, `gstin`, `pan`}, `gstRegistrationType` (`registered` | `unregistered`), `creditDays` (0-9999), `creditLimit` (> 0), `openingBalance`.\n\n**Opening balance** (part of the books, optional): `{ \"amount\": 300, \"type\": \"debit\"|\"credit\", \"allocation\": \"billWise\"|\"unallocated\", \"billReferences\": [ { \"number\": \"OB-0001\", \"date\": \"2026-03-15\", \"dueDate\": \"2026-04-15\", \"amount\": 300, \"type\": \"debit\" } ] }`. `allocation` is required: `billWise` needs bill references whose signed total equals the balance (dates on or before 1 April of the year, at most 50); `unallocated` allows none and says so in `metadata.openingBalanceAllocation`. The example body leaves it out on purpose.\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }` (each field sent, as BUSY stored it; references with the code BUSY resolved); `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType, outcome (created), verifiedFields, [openingBalanceAllocation], elapsedMs, executedAt`. The test stores `masterAccountId` / `masterAccountName` for the modify request.\n\n**Errors:** 400 `BAD_REQUEST`, `INVALID_PARAMETER` (`field`); 404 `COMPANY_NOT_CONFIGURED`; 409 `MASTER_NAME_TAKEN`, `MASTER_WRITE_PROVIDER_UNSUPPORTED`, `COMPANY_DISABLED`, `FINANCIAL_YEAR_NOT_ALLOWED`; 422 `MASTER_REFERENCE_NOT_FOUND`, `MASTER_REFERENCE_AMBIGUOUS`; 502 `BUSY_WRITE_FAILED`, `BUSY_WRITE_UNVERIFIED`; 503 `BUSY_COM_*` prerequisites, `BUSY_COM_QUEUE_TIMEOUT`; 504 `BUSY_WRITE_UNCERTAIN`, `BUSY_COM_TIMEOUT`.\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab; customer guide `docs/public/api/account-and-product-masters.md`.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Accounts: on **Access companies** also dropdown, whole-number, date and Yes/No fields, with the product rules below (create a new account dropdown value first with **⚠ BUSY account dropdown value – create**); on **SQL Server companies** free-text fields only — the other account kinds are refused with `422 OPTIONAL_FIELD_UNSUPPORTED` (proven on Access, not yet on SQL Server). On a create, `null` is refused. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\n\n## FULL synthetic optional-field request example (Local only)\nThe raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check `/optional-field-definitions` before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, `null` clears OF1; omitted slots remain unchanged. On create, `null` is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.\n```json\n{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Account 01\",\n  \"alias\": \"AZAPI-ACC-01\",\n  \"parentGroup\": {\n    \"name\": \"Sundry Debtors\"\n  },\n  \"address\": {\n    \"line1\": \"1 Example Road\",\n    \"state\": {\n      \"name\": \"Delhi\"\n    },\n    \"pinCode\": \"110001\",\n    \"mobile\": \"9000000000\",\n    \"email\": \"accounts@example.invalid\"\n  },\n  \"gstRegistrationType\": \"unregistered\",\n  \"creditDays\": 15,\n  \"creditLimit\": 25000,\n  \"optionalFields\": {\n    \"OF1\": \"Synthetic customer class\"\n  }\n}\n```\n\r\n\r\nOriginal destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e11"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"MASTER_NAME_TAKEN\",\n      \"message\": \"BUSY already has a master of this type whose name or alias equals this name. A create never changes an existing master.\",\n      \"field\": \"name\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e11\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"74203354-b2ca-70f0-17e9-6dde66410103","name":"504 – outcome unknown (BUSY_WRITE_UNCERTAIN; do not retry)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Account 01\",\n  \"alias\": \"AZAPI-ACC-01\",\n  \"parentGroup\": { \"name\": \"Sundry Debtors\" },\n  \"address\": {\n    \"line1\": \"1 Example Road\",\n    \"state\": { \"name\": \"Delhi\" },\n    \"pinCode\": \"110001\",\n    \"mobile\": \"9000000000\",\n    \"email\": \"accounts@example.invalid\"\n  },\n  \"gstRegistrationType\": \"unregistered\",\n  \"creditDays\": 15,\n  \"creditLimit\": 25000\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-create","description":"**Local** · `POST {{baseUrl}}/api/v1/account-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `name`, `parentGroup` · operation `busy.accounts.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.accounts.create` (`POST /api/v1/account-create`) creates one BUSY account (ledger) through BUSY's own COM component on this PC, then reads it back from BUSY and checks every field you sent before answering. **SQL Server companies with a SQL login, or Access companies**. Never an upsert. Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Use only a **development-test company** (`targetCompanyCode`, e.g. COMP0002 on the development PC) and a **new, unique test name** (change `name` and `alias` before each send). Never a customer's company.\n- Nothing is deleted automatically: a created test account stays in BUSY. Remove it in BUSY yourself if needed.\n- **Never retry a write blindly.** A second send of the same body is refused (`409 MASTER_NAME_TAKEN`) if the first saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `masterId`, `notFound`, `notChecked`) and look the account up (Customers) before anything else.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back differs (`details.masterId`, `details.mismatchedFields`): check it in BUSY.\n- One BUSY job at a time on the PC (shared with voucher PDFs), up to 2 minutes: give the request a long timeout.\n\n**Body:** `companyCode`, `financialYear`, `name` (1-40, required), `alias`, `printName` (1-60), `parentGroup` (required, `{\"code\": n}` or `{\"name\": \"…\"}`), `address` {`line1`…`line4`, `state`, `pinCode`, `station`, `contactPerson`, `telephone`, `mobile`, `whatsApp`, `email`, `gstin`, `pan`}, `gstRegistrationType` (`registered` | `unregistered`), `creditDays` (0-9999), `creditLimit` (> 0), `openingBalance`.\n\n**Opening balance** (part of the books, optional): `{ \"amount\": 300, \"type\": \"debit\"|\"credit\", \"allocation\": \"billWise\"|\"unallocated\", \"billReferences\": [ { \"number\": \"OB-0001\", \"date\": \"2026-03-15\", \"dueDate\": \"2026-04-15\", \"amount\": 300, \"type\": \"debit\" } ] }`. `allocation` is required: `billWise` needs bill references whose signed total equals the balance (dates on or before 1 April of the year, at most 50); `unallocated` allows none and says so in `metadata.openingBalanceAllocation`. The example body leaves it out on purpose.\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }` (each field sent, as BUSY stored it; references with the code BUSY resolved); `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType, outcome (created), verifiedFields, [openingBalanceAllocation], elapsedMs, executedAt`. The test stores `masterAccountId` / `masterAccountName` for the modify request.\n\n**Errors:** 400 `BAD_REQUEST`, `INVALID_PARAMETER` (`field`); 404 `COMPANY_NOT_CONFIGURED`; 409 `MASTER_NAME_TAKEN`, `MASTER_WRITE_PROVIDER_UNSUPPORTED`, `COMPANY_DISABLED`, `FINANCIAL_YEAR_NOT_ALLOWED`; 422 `MASTER_REFERENCE_NOT_FOUND`, `MASTER_REFERENCE_AMBIGUOUS`; 502 `BUSY_WRITE_FAILED`, `BUSY_WRITE_UNVERIFIED`; 503 `BUSY_COM_*` prerequisites, `BUSY_COM_QUEUE_TIMEOUT`; 504 `BUSY_WRITE_UNCERTAIN`, `BUSY_COM_TIMEOUT`.\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab; customer guide `docs/public/api/account-and-product-masters.md`.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Accounts: on **Access companies** also dropdown, whole-number, date and Yes/No fields, with the product rules below (create a new account dropdown value first with **⚠ BUSY account dropdown value – create**); on **SQL Server companies** free-text fields only — the other account kinds are refused with `422 OPTIONAL_FIELD_UNSUPPORTED` (proven on Access, not yet on SQL Server). On a create, `null` is refused. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\n\n## FULL synthetic optional-field request example (Local only)\nThe raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check `/optional-field-definitions` before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, `null` clears OF1; omitted slots remain unchanged. On create, `null` is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.\n```json\n{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Account 01\",\n  \"alias\": \"AZAPI-ACC-01\",\n  \"parentGroup\": {\n    \"name\": \"Sundry Debtors\"\n  },\n  \"address\": {\n    \"line1\": \"1 Example Road\",\n    \"state\": {\n      \"name\": \"Delhi\"\n    },\n    \"pinCode\": \"110001\",\n    \"mobile\": \"9000000000\",\n    \"email\": \"accounts@example.invalid\"\n  },\n  \"gstRegistrationType\": \"unregistered\",\n  \"creditDays\": 15,\n  \"creditLimit\": 25000,\n  \"optionalFields\": {\n    \"OF1\": \"Synthetic customer class\"\n  }\n}\n```\n\r\n\r\nOriginal destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e12"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"BUSY stopped while saving the master, so whether it was saved is not known. Check the master in BUSY (or read it through the Local API) before trying again.\",\n      \"details\": {\n        \"masterId\": 7001,\n        \"reconciliation\": \"found\"\n      }\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e12\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"56075f44-f70e-6055-1e71-f37a0ff7ce04","name":"409 – optional-field configuration changed (no write)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP0001\",\n  \"financialYear\": \"2026\",\n  \"name\": \"Synthetic account\",\n  \"parentGroup\": {\n    \"name\": \"Sundry Debtors\"\n  },\n  \"optionalFields\": {\n    \"OF1\": \"Synthetic value\"\n  }\n}"},"url":"{{baseUrl}}/api/v1/account-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"OPTIONAL_FIELD_CONFIGURATION_CHANGED\",\n      \"message\": \"BUSY's optional-field configuration changed while this master write was being prepared. Nothing was written. Read the definitions and prepare a new request.\",\n      \"field\": \"optionalFields\"\n    },\n    \"requestId\": \"00000000000000000000000000000001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"26a0ef1d-e35f-4de0-4dde-ffa2a9fd1050","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Account 01\",\n  \"alias\": \"AZAPI-ACC-01\",\n  \"parentGroup\": {\n    \"name\": \"Sundry Debtors\"\n  },\n  \"address\": {\n    \"line1\": \"1 Example Road\",\n    \"state\": {\n      \"name\": \"Delhi\"\n    },\n    \"pinCode\": \"110001\",\n    \"mobile\": \"9000000000\",\n    \"email\": \"accounts@example.invalid\"\n  },\n  \"gstRegistrationType\": \"unregistered\",\n  \"creditDays\": 15,\n  \"creditLimit\": 25000,\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-create"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"synthetic-queue-001"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.accounts.create\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"},{"id":"9aba4405-c136-402b-b486-390c20656c63","name":"409 - BUSY_WRITE_TARGET_CHANGED (synthetic; before save)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/account-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"BUSY_WRITE_TARGET_CHANGED\",\"message\":\"The BUSY destination or its permissions changed before helper execution; nothing was saved.\"}}}"},{"id":"71c06b1d-ede8-41c8-9a59-b59ca05a5caf","name":"409 - MASTER_REFERENCE_CHANGED (synthetic; before save)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/account-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"MASTER_REFERENCE_CHANGED\",\"message\":\"An ordinary master reference changed before the save; nothing was saved. Read the references again.\"}}}"}],"_postman_id":"e1632973-b0d3-c1d8-a51c-72991e1139f6"},{"name":"⚠ BUSY master – modify account (writes to BUSY)","id":"5b69264d-1d60-905c-afbc-03e04989f207","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"accountId\": {{masterAccountId}},\n  \"expectedName\": \"{{masterAccountName}}\",\n  \"address\": {\n    \"mobile\": \"9000000001\"\n  },\n  \"creditLimit\": 30000\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-modify","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/account-modify</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>)\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>accountId</code> · operation <code>busy.accounts.modify</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq). An account modify keeps a WhatsApp number you do not send exactly as BUSY stores it (never BUSY's displayed \"91\" + mobile).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books. Run manually, one at a time.</strong> <code>busy.accounts.modify</code> (<code>POST /api/v1/account-modify</code>) changes only the fields you send of one existing BUSY account, named by BUSY's code (<code>accountId</code> = <code>customer_id</code> in the customer operations). BUSY's own record is read, edited and saved; every other field stays as it is, and the record is compared before and after (an unrequested change is reported as <code>BUSY_WRITE_UNVERIFIED</code>). Not relayed by the current Windows build (the cloud route exists since cloud <code>3b13ab1</code>, but this PC refuses relayed writes: see Cloud → ⚠ Master Create &amp; Modify); never run from scripts.</p>\n<p><strong>Safe test guidance</strong></p>\n<ul>\n<li>Change <strong>only a test account you created yourself</strong> — the create request stores <code>masterAccountId</code> and <code>masterAccountName</code>. Never a customer's account. The pre-request script skips the request when either variable is empty.</li>\n<li>Always send <code>expectedName</code>: if the account's name in BUSY differs, nothing is changed (<code>409 MASTER_NAME_MISMATCH</code>).</li>\n<li><strong>Never retry a write blindly.</strong> After <code>504 BUSY_WRITE_UNCERTAIN</code>, read the account first (Customer with <code>customerId</code> = <code>accountId</code>) and compare.</li>\n</ul>\n<p><strong>Changeable:</strong> <code>printName</code>, any <code>address</code> member (<code>line1</code>…<code>line4</code>, <code>state</code>, <code>pinCode</code>, <code>station</code>, <code>contactPerson</code>, <code>telephone</code>, <code>mobile</code>, <code>whatsApp</code>, <code>email</code>, <code>gstin</code>, <code>pan</code>), <code>gstRegistrationType</code>, <code>creditDays</code>, <code>creditLimit</code>, and <code>openingBalance</code> with <code>allocation: \"unallocated\"</code> <strong>only</strong> for an account with no opening bill references (otherwise <code>409 MASTER_CHANGE_UNSUPPORTED</code>). <strong>Not changeable here:</strong> name, alias, group, bill references. A body with nothing to change is <code>400</code>.</p>\n<p><strong>Answer (200):</strong> <code>data</code> = <code>{ masterId, name, alias, fields }</code> (<code>fields</code> = only the fields sent, as BUSY stored them); <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, masterType, outcome (modified), verifiedFields, [openingBalanceAllocation], elapsedMs, executedAt</code>.</p>\n<p><strong>Errors:</strong> as create, plus 404 <code>NOT_FOUND</code> (no master with that code, <code>field: accountId</code>), 409 <code>MASTER_TYPE_MISMATCH</code> (the code is not an account), <code>MASTER_NAME_MISMATCH</code>, <code>MASTER_CHANGE_UNSUPPORTED</code>.</p>\n<p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5ab.</p>\n<p><strong>Optional fields (since 2026-10-17):</strong> optional member <code>optionalFields</code>. Keyed <code>OF1</code>–<code>OF10</code> (read the slots with <strong>busy.optional-fields.definitions</strong> for the same year first); the slot must be defined for this master type in that year (<code>422 OPTIONAL_FIELD_NOT_DEFINED</code>). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Accounts: on <strong>Access companies</strong> also dropdown, whole-number, date and Yes/No fields, with the product rules below (create a new account dropdown value first with <strong>⚠ BUSY account dropdown value – create</strong>); on <strong>SQL Server companies</strong> free-text fields only — the other account kinds are refused with <code>422 OPTIONAL_FIELD_UNSUPPORTED</code> (proven on Access, not yet on SQL Server). On a modify, omitted slots keep their values, <code>null</code> clears a slot, an empty string is refused; only the slot elements of BUSY's own record are edited. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (<code>502 BUSY_WRITE_UNVERIFIED</code> names <code>optionalFields.OF</code>n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract <code>docs/LOCAL-API.md</code> 5an; guide <code>docs/public/api/optional-fields.md</code>.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n<h2 id=\"full-synthetic-optional-field-request-example-local-only\">FULL synthetic optional-field request example (Local only)</h2>\n<p>The raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check <code>/optional-field-definitions</code> before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, <code>null</code> clears OF1; omitted slots remain unchanged. On create, <code>null</code> is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"accountId\": \"{{masterAccountId}}\",\n  \"expectedName\": \"{{masterAccountName}}\",\n  \"address\": {\n    \"mobile\": \"9000000001\"\n  },\n  \"creditLimit\": 30000,\n  \"optionalFields\": {\n    \"OF1\": null\n  }\n}\n</code></pre>\n<p>Original destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","account-modify"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"39ac7409-5426-a58f-2734-7ec6fa47a8b3","name":"200 – account modified and verified (synthetic example)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"accountId\": {{masterAccountId}},\n  \"expectedName\": \"{{masterAccountName}}\",\n  \"address\": {\n    \"mobile\": \"9000000001\"\n  },\n  \"creditLimit\": 30000\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/account-modify` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `accountId` · operation `busy.accounts.modify`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). An account modify keeps a WhatsApp number you do not send exactly as BUSY stores it (never BUSY's displayed \"91\" + mobile).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.accounts.modify` (`POST /api/v1/account-modify`) changes only the fields you send of one existing BUSY account, named by BUSY's code (`accountId` = `customer_id` in the customer operations). BUSY's own record is read, edited and saved; every other field stays as it is, and the record is compared before and after (an unrequested change is reported as `BUSY_WRITE_UNVERIFIED`). Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Change **only a test account you created yourself** — the create request stores `masterAccountId` and `masterAccountName`. Never a customer's account. The pre-request script skips the request when either variable is empty.\n- Always send `expectedName`: if the account's name in BUSY differs, nothing is changed (`409 MASTER_NAME_MISMATCH`).\n- **Never retry a write blindly.** After `504 BUSY_WRITE_UNCERTAIN`, read the account first (Customer with `customerId` = `accountId`) and compare.\n\n**Changeable:** `printName`, any `address` member (`line1`…`line4`, `state`, `pinCode`, `station`, `contactPerson`, `telephone`, `mobile`, `whatsApp`, `email`, `gstin`, `pan`), `gstRegistrationType`, `creditDays`, `creditLimit`, and `openingBalance` with `allocation: \"unallocated\"` **only** for an account with no opening bill references (otherwise `409 MASTER_CHANGE_UNSUPPORTED`). **Not changeable here:** name, alias, group, bill references. A body with nothing to change is `400`.\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }` (`fields` = only the fields sent, as BUSY stored them); `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType, outcome (modified), verifiedFields, [openingBalanceAllocation], elapsedMs, executedAt`.\n\n**Errors:** as create, plus 404 `NOT_FOUND` (no master with that code, `field: accountId`), 409 `MASTER_TYPE_MISMATCH` (the code is not an account), `MASTER_NAME_MISMATCH`, `MASTER_CHANGE_UNSUPPORTED`.\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Accounts: on **Access companies** also dropdown, whole-number, date and Yes/No fields, with the product rules below (create a new account dropdown value first with **⚠ BUSY account dropdown value – create**); on **SQL Server companies** free-text fields only — the other account kinds are refused with `422 OPTIONAL_FIELD_UNSUPPORTED` (proven on Access, not yet on SQL Server). On a modify, omitted slots keep their values, `null` clears a slot, an empty string is refused; only the slot elements of BUSY's own record are edited. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\n\n## FULL synthetic optional-field request example (Local only)\nThe raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check `/optional-field-definitions` before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, `null` clears OF1; omitted slots remain unchanged. On create, `null` is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.\n```json\n{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"accountId\": \"{{masterAccountId}}\",\n  \"expectedName\": \"{{masterAccountName}}\",\n  \"address\": {\n    \"mobile\": \"9000000001\"\n  },\n  \"creditLimit\": 30000,\n  \"optionalFields\": {\n    \"OF1\": null\n  }\n}\n```\n\r\n\r\nOriginal destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e13","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"masterId\": 7001,\n    \"name\": \"AZAPI Test Account 01\",\n    \"alias\": \"AZAPI-ACC-01\",\n    \"fields\": {\n      \"address.mobile\": \"9000000001\",\n      \"creditLimit\": 30000\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.accounts.modify\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e13\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"masterType\": \"account\",\n    \"outcome\": \"modified\",\n    \"verifiedFields\": [\"address.mobile\", \"creditLimit\"],\n    \"elapsedMs\": 3890,\n    \"executedAt\": \"2026-09-26T10:00:00+00:00\"\n  }\n}"},{"id":"808f6c5a-2bcd-a221-ba12-3ce2581293a2","name":"409 – expectedName differs (MASTER_NAME_MISMATCH; nothing changed)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"accountId\": {{masterAccountId}},\n  \"expectedName\": \"{{masterAccountName}}\",\n  \"address\": {\n    \"mobile\": \"9000000001\"\n  },\n  \"creditLimit\": 30000\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/account-modify` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `accountId` · operation `busy.accounts.modify`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). An account modify keeps a WhatsApp number you do not send exactly as BUSY stores it (never BUSY's displayed \"91\" + mobile).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.accounts.modify` (`POST /api/v1/account-modify`) changes only the fields you send of one existing BUSY account, named by BUSY's code (`accountId` = `customer_id` in the customer operations). BUSY's own record is read, edited and saved; every other field stays as it is, and the record is compared before and after (an unrequested change is reported as `BUSY_WRITE_UNVERIFIED`). Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Change **only a test account you created yourself** — the create request stores `masterAccountId` and `masterAccountName`. Never a customer's account. The pre-request script skips the request when either variable is empty.\n- Always send `expectedName`: if the account's name in BUSY differs, nothing is changed (`409 MASTER_NAME_MISMATCH`).\n- **Never retry a write blindly.** After `504 BUSY_WRITE_UNCERTAIN`, read the account first (Customer with `customerId` = `accountId`) and compare.\n\n**Changeable:** `printName`, any `address` member (`line1`…`line4`, `state`, `pinCode`, `station`, `contactPerson`, `telephone`, `mobile`, `whatsApp`, `email`, `gstin`, `pan`), `gstRegistrationType`, `creditDays`, `creditLimit`, and `openingBalance` with `allocation: \"unallocated\"` **only** for an account with no opening bill references (otherwise `409 MASTER_CHANGE_UNSUPPORTED`). **Not changeable here:** name, alias, group, bill references. A body with nothing to change is `400`.\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }` (`fields` = only the fields sent, as BUSY stored them); `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType, outcome (modified), verifiedFields, [openingBalanceAllocation], elapsedMs, executedAt`.\n\n**Errors:** as create, plus 404 `NOT_FOUND` (no master with that code, `field: accountId`), 409 `MASTER_TYPE_MISMATCH` (the code is not an account), `MASTER_NAME_MISMATCH`, `MASTER_CHANGE_UNSUPPORTED`.\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Accounts: on **Access companies** also dropdown, whole-number, date and Yes/No fields, with the product rules below (create a new account dropdown value first with **⚠ BUSY account dropdown value – create**); on **SQL Server companies** free-text fields only — the other account kinds are refused with `422 OPTIONAL_FIELD_UNSUPPORTED` (proven on Access, not yet on SQL Server). On a modify, omitted slots keep their values, `null` clears a slot, an empty string is refused; only the slot elements of BUSY's own record are edited. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\n\n## FULL synthetic optional-field request example (Local only)\nThe raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check `/optional-field-definitions` before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, `null` clears OF1; omitted slots remain unchanged. On create, `null` is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.\n```json\n{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"accountId\": \"{{masterAccountId}}\",\n  \"expectedName\": \"{{masterAccountName}}\",\n  \"address\": {\n    \"mobile\": \"9000000001\"\n  },\n  \"creditLimit\": 30000,\n  \"optionalFields\": {\n    \"OF1\": null\n  }\n}\n```\n\r\n\r\nOriginal destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e14"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"MASTER_NAME_MISMATCH\",\n      \"message\": \"The master's name in BUSY is not expectedName; nothing was changed.\",\n      \"field\": \"expectedName\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e14\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"eb80d028-4156-5126-1abe-45a2602c89cc","name":"409 – opening balance on an account with bill references (MASTER_CHANGE_UNSUPPORTED)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"accountId\": {{masterAccountId}},\n  \"expectedName\": \"{{masterAccountName}}\",\n  \"address\": {\n    \"mobile\": \"9000000001\"\n  },\n  \"creditLimit\": 30000\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/account-modify` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `accountId` · operation `busy.accounts.modify`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). An account modify keeps a WhatsApp number you do not send exactly as BUSY stores it (never BUSY's displayed \"91\" + mobile).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.accounts.modify` (`POST /api/v1/account-modify`) changes only the fields you send of one existing BUSY account, named by BUSY's code (`accountId` = `customer_id` in the customer operations). BUSY's own record is read, edited and saved; every other field stays as it is, and the record is compared before and after (an unrequested change is reported as `BUSY_WRITE_UNVERIFIED`). Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Change **only a test account you created yourself** — the create request stores `masterAccountId` and `masterAccountName`. Never a customer's account. The pre-request script skips the request when either variable is empty.\n- Always send `expectedName`: if the account's name in BUSY differs, nothing is changed (`409 MASTER_NAME_MISMATCH`).\n- **Never retry a write blindly.** After `504 BUSY_WRITE_UNCERTAIN`, read the account first (Customer with `customerId` = `accountId`) and compare.\n\n**Changeable:** `printName`, any `address` member (`line1`…`line4`, `state`, `pinCode`, `station`, `contactPerson`, `telephone`, `mobile`, `whatsApp`, `email`, `gstin`, `pan`), `gstRegistrationType`, `creditDays`, `creditLimit`, and `openingBalance` with `allocation: \"unallocated\"` **only** for an account with no opening bill references (otherwise `409 MASTER_CHANGE_UNSUPPORTED`). **Not changeable here:** name, alias, group, bill references. A body with nothing to change is `400`.\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }` (`fields` = only the fields sent, as BUSY stored them); `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType, outcome (modified), verifiedFields, [openingBalanceAllocation], elapsedMs, executedAt`.\n\n**Errors:** as create, plus 404 `NOT_FOUND` (no master with that code, `field: accountId`), 409 `MASTER_TYPE_MISMATCH` (the code is not an account), `MASTER_NAME_MISMATCH`, `MASTER_CHANGE_UNSUPPORTED`.\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Accounts: on **Access companies** also dropdown, whole-number, date and Yes/No fields, with the product rules below (create a new account dropdown value first with **⚠ BUSY account dropdown value – create**); on **SQL Server companies** free-text fields only — the other account kinds are refused with `422 OPTIONAL_FIELD_UNSUPPORTED` (proven on Access, not yet on SQL Server). On a modify, omitted slots keep their values, `null` clears a slot, an empty string is refused; only the slot elements of BUSY's own record are edited. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\n\n## FULL synthetic optional-field request example (Local only)\nThe raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check `/optional-field-definitions` before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, `null` clears OF1; omitted slots remain unchanged. On create, `null` is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.\n```json\n{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"accountId\": \"{{masterAccountId}}\",\n  \"expectedName\": \"{{masterAccountName}}\",\n  \"address\": {\n    \"mobile\": \"9000000001\"\n  },\n  \"creditLimit\": 30000,\n  \"optionalFields\": {\n    \"OF1\": null\n  }\n}\n```\n\r\n\r\nOriginal destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e15","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"MASTER_CHANGE_UNSUPPORTED\",\n      \"message\": \"This account has opening bill references in BUSY; changing its opening balance is not offered, because how BUSY updates existing references was not tested. Change it in BUSY.\",\n      \"field\": \"openingBalance\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e15\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"1bb696e2-644f-f5fe-65ab-4ccb49585f10","name":"422 – account dropdown field (OPTIONAL_FIELD_UNSUPPORTED; not proven, nothing written)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"accountId\": {{masterAccountId}},\n  \"expectedName\": \"{{masterAccountName}}\",\n  \"address\": {\n    \"mobile\": \"9000000001\"\n  },\n  \"creditLimit\": 30000\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/account-modify` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `accountId` · operation `busy.accounts.modify`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). An account modify keeps a WhatsApp number you do not send exactly as BUSY stores it (never BUSY's displayed \"91\" + mobile).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.accounts.modify` (`POST /api/v1/account-modify`) changes only the fields you send of one existing BUSY account, named by BUSY's code (`accountId` = `customer_id` in the customer operations). BUSY's own record is read, edited and saved; every other field stays as it is, and the record is compared before and after (an unrequested change is reported as `BUSY_WRITE_UNVERIFIED`). Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Change **only a test account you created yourself** — the create request stores `masterAccountId` and `masterAccountName`. Never a customer's account. The pre-request script skips the request when either variable is empty.\n- Always send `expectedName`: if the account's name in BUSY differs, nothing is changed (`409 MASTER_NAME_MISMATCH`).\n- **Never retry a write blindly.** After `504 BUSY_WRITE_UNCERTAIN`, read the account first (Customer with `customerId` = `accountId`) and compare.\n\n**Changeable:** `printName`, any `address` member (`line1`…`line4`, `state`, `pinCode`, `station`, `contactPerson`, `telephone`, `mobile`, `whatsApp`, `email`, `gstin`, `pan`), `gstRegistrationType`, `creditDays`, `creditLimit`, and `openingBalance` with `allocation: \"unallocated\"` **only** for an account with no opening bill references (otherwise `409 MASTER_CHANGE_UNSUPPORTED`). **Not changeable here:** name, alias, group, bill references. A body with nothing to change is `400`.\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }` (`fields` = only the fields sent, as BUSY stored them); `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType, outcome (modified), verifiedFields, [openingBalanceAllocation], elapsedMs, executedAt`.\n\n**Errors:** as create, plus 404 `NOT_FOUND` (no master with that code, `field: accountId`), 409 `MASTER_TYPE_MISMATCH` (the code is not an account), `MASTER_NAME_MISMATCH`, `MASTER_CHANGE_UNSUPPORTED`.\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Accounts: on **Access companies** also dropdown, whole-number, date and Yes/No fields, with the product rules below (create a new account dropdown value first with **⚠ BUSY account dropdown value – create**); on **SQL Server companies** free-text fields only — the other account kinds are refused with `422 OPTIONAL_FIELD_UNSUPPORTED` (proven on Access, not yet on SQL Server). On a modify, omitted slots keep their values, `null` clears a slot, an empty string is refused; only the slot elements of BUSY's own record are edited. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\n\n## FULL synthetic optional-field request example (Local only)\nThe raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check `/optional-field-definitions` before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, `null` clears OF1; omitted slots remain unchanged. On create, `null` is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.\n```json\n{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"accountId\": \"{{masterAccountId}}\",\n  \"expectedName\": \"{{masterAccountName}}\",\n  \"address\": {\n    \"mobile\": \"9000000001\"\n  },\n  \"creditLimit\": 30000,\n  \"optionalFields\": {\n    \"OF1\": null\n  }\n}\n```\n\r\n\r\nOriginal destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"OPTIONAL_FIELD_UNSUPPORTED\",\n      \"message\": \"Account dropdown fields are not supported yet: BUSY's account value lists were not proven (a dedicated test is pending). Set the value in BUSY. Nothing was written.\",\n      \"field\": \"optionalFields.OF1\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e27\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"fe1a95ec-c0ed-1fe5-e05d-f1f81b7fe633","name":"409 – optional-field configuration changed (no write)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP0001\",\n  \"financialYear\": \"2026\",\n  \"accountId\": 1234,\n  \"expectedName\": \"Synthetic Account\",\n  \"optionalFields\": {\n    \"OF1\": \"Synthetic value\"\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/account-modify` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `accountId` · operation `busy.accounts.modify`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). An account modify keeps a WhatsApp number you do not send exactly as BUSY stores it (never BUSY's displayed \"91\" + mobile).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.accounts.modify` (`POST /api/v1/account-modify`) changes only the fields you send of one existing BUSY account, named by BUSY's code (`accountId` = `customer_id` in the customer operations). BUSY's own record is read, edited and saved; every other field stays as it is, and the record is compared before and after (an unrequested change is reported as `BUSY_WRITE_UNVERIFIED`). Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Change **only a test account you created yourself** — the create request stores `masterAccountId` and `masterAccountName`. Never a customer's account. The pre-request script skips the request when either variable is empty.\n- Always send `expectedName`: if the account's name in BUSY differs, nothing is changed (`409 MASTER_NAME_MISMATCH`).\n- **Never retry a write blindly.** After `504 BUSY_WRITE_UNCERTAIN`, read the account first (Customer with `customerId` = `accountId`) and compare.\n\n**Changeable:** `printName`, any `address` member (`line1`…`line4`, `state`, `pinCode`, `station`, `contactPerson`, `telephone`, `mobile`, `whatsApp`, `email`, `gstin`, `pan`), `gstRegistrationType`, `creditDays`, `creditLimit`, and `openingBalance` with `allocation: \"unallocated\"` **only** for an account with no opening bill references (otherwise `409 MASTER_CHANGE_UNSUPPORTED`). **Not changeable here:** name, alias, group, bill references. A body with nothing to change is `400`.\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }` (`fields` = only the fields sent, as BUSY stored them); `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType, outcome (modified), verifiedFields, [openingBalanceAllocation], elapsedMs, executedAt`.\n\n**Errors:** as create, plus 404 `NOT_FOUND` (no master with that code, `field: accountId`), 409 `MASTER_TYPE_MISMATCH` (the code is not an account), `MASTER_NAME_MISMATCH`, `MASTER_CHANGE_UNSUPPORTED`.\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Accounts: on **Access companies** also dropdown, whole-number, date and Yes/No fields, with the product rules below (create a new account dropdown value first with **⚠ BUSY account dropdown value – create**); on **SQL Server companies** free-text fields only — the other account kinds are refused with `422 OPTIONAL_FIELD_UNSUPPORTED` (proven on Access, not yet on SQL Server). On a modify, omitted slots keep their values, `null` clears a slot, an empty string is refused; only the slot elements of BUSY's own record are edited. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"OPTIONAL_FIELD_CONFIGURATION_CHANGED\",\n      \"message\": \"BUSY's optional-field configuration changed while this master write was being prepared. Nothing was written. Read the definitions and prepare a new request.\",\n      \"field\": \"optionalFields\"\n    },\n    \"requestId\": \"00000000000000000000000000000001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"fd704d3d-5851-77e0-4bd4-44be03564977","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"accountId\": {{masterAccountId}},\n  \"expectedName\": \"{{masterAccountName}}\",\n  \"address\": {\n    \"mobile\": \"9000000001\"\n  },\n  \"creditLimit\": 30000,\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-modify"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"synthetic-queue-001"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.accounts.modify\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"},{"id":"061c2160-13f8-4620-88b7-e3c9ef552a09","name":"409 - BUSY_WRITE_TARGET_CHANGED (synthetic; before save)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/account-modify"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"BUSY_WRITE_TARGET_CHANGED\",\"message\":\"The BUSY destination or its permissions changed before helper execution; nothing was saved.\"}}}"},{"id":"a751e61c-e414-4d19-9ee1-8542a49a0dc4","name":"409 - MASTER_REFERENCE_CHANGED (synthetic; before save)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/account-modify"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"MASTER_REFERENCE_CHANGED\",\"message\":\"An ordinary master reference changed before the save; nothing was saved. Read the references again.\"}}}"}],"_postman_id":"5b69264d-1d60-905c-afbc-03e04989f207"},{"name":"⚠ BUSY master – create product (writes to BUSY)","id":"941c11bd-e159-9efe-4787-ed47a1d7ddaa","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Item 01\",\n  \"alias\": \"AZAPI-ITEM-01\",\n  \"parentGroup\": { \"name\": \"General\" },\n  \"mainUnit\": { \"name\": \"Pcs.\" },\n  \"salePrice\": 150,\n  \"purchasePrice\": 100,\n  \"mrp\": 200,\n  \"hsnCode\": \"84713010\",\n  \"descriptionLines\": [\"Synthetic test item\"]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-create","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/product-create</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>)\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>name</code>, <code>parentGroup</code>, <code>mainUnit</code> · operation <code>busy.products.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq). An <code>alternateUnit</code> needs BUSY's \"Alternate Unit of Items\" option (else <code>422 BUSY_SETTING_REQUIRED</code>, field <code>alternateUnit</code>; <code>502 BUSY_SETTINGS_UNREADABLE</code> when BUSY's configuration cannot be read).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books. Run manually, one at a time.</strong> <code>busy.products.create</code> (<code>POST /api/v1/product-create</code>) creates one BUSY product (item) through BUSY's own COM component on this PC, then reads it back and checks every field you sent before answering. Never an upsert. Not relayed by the current Windows build (the cloud route exists since cloud <code>3b13ab1</code>, but this PC refuses relayed writes: see Cloud → ⚠ Master Create &amp; Modify); never run from scripts.</p>\n<p><strong>Safe test guidance</strong></p>\n<ul>\n<li>Use only a <strong>development-test company</strong> (<code>targetCompanyCode</code>) and a <strong>new, unique test name</strong> (change <code>name</code> and <code>alias</code> before each send). Never a customer's company. Created test products stay in BUSY.</li>\n<li>The example sends <strong>no opening stock</strong> on purpose (it is part of the books). Add it only on a test product, deliberately.</li>\n<li><strong>Never retry a write blindly</strong>: a second send of the same body is refused (<code>409 MASTER_NAME_TAKEN</code>) if the first saved; after <code>504 BUSY_WRITE_UNCERTAIN</code> look the product up (Products search) first.</li>\n<li>References (<code>parentGroup</code>, <code>mainUnit</code>, <code>alternateUnit.unit</code>, <code>taxCategory</code>, <code>openingStock.materialCenter</code>) must exist in the company; a name more than one master shares is <code>422 MASTER_REFERENCE_AMBIGUOUS</code>.</li>\n</ul>\n<p><strong>Body:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>name</code> (1-40, required), <code>alias</code>, <code>printName</code> (1-60), <code>parentGroup</code> (required, item group <code>{\"code\": n}</code> or <code>{\"name\": \"…\"}</code>), <code>mainUnit</code> (required), <code>alternateUnit</code> (<code>{\"unit\": {\"name\": \"Dozen\"}, \"conversionFactor\": 12}</code>), <code>salePrice</code>, <code>purchasePrice</code>, <code>mrp</code> (≥ 0, ≤ 4 decimals), <code>salesDiscountPercent</code>, <code>purchaseDiscountPercent</code> (0-100), <code>hsnCode</code> (4-8 digits), <code>taxCategory</code> (e.g. <code>{\"name\": \"GST 18%\"}</code>; BUSY sets the rates from it), <code>descriptionLines</code> (1-4 lines of 1-40), <code>openingStock</code> (<code>{\"quantity\": 10, \"amount\": 1000, \"materialCenter\": {\"name\": \"Main Store\"}}</code>; one godown, conversion factor 1 only).</p>\n<p><strong>Answer (200):</strong> <code>data</code> = <code>{ masterId, name, alias, fields }</code>; <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, masterType (product), outcome (created), verifiedFields, elapsedMs, executedAt</code>. The test stores <code>masterProductId</code> / <code>masterProductName</code> for the modify request.</p>\n<p><strong>Errors:</strong> as account create (400, 403, 404, 409 <code>MASTER_NAME_TAKEN</code> / <code>MASTER_WRITE_PROVIDER_UNSUPPORTED</code>, 422 references, 502 <code>BUSY_WRITE_FAILED</code> / <code>BUSY_WRITE_UNVERIFIED</code>, 503 <code>BUSY_COM_*</code>, 504 <code>BUSY_WRITE_UNCERTAIN</code> / <code>BUSY_COM_TIMEOUT</code>).</p>\n<p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5ab.</p>\n<p><strong>Optional fields (since 2026-10-17):</strong> optional member <code>optionalFields</code>. Keyed <code>OF1</code>–<code>OF10</code> (read the slots with <strong>busy.optional-fields.definitions</strong> for the same year first); the slot must be defined for this master type in that year (<code>422 OPTIONAL_FIELD_NOT_DEFINED</code>). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Products: text; a dropdown as <code>{\"code\": n}</code> or <code>{\"name\": \"…\"}</code> of an <strong>existing</strong> value of that slot's own list (unknown <code>422 OPTIONAL_FIELD_VALUE_NOT_FOUND</code>: BUSY would add it silently — create it first with <strong>⚠ BUSY product dropdown value – create</strong>); a whole number from -999999999999 to 999999999999 (12 digits, the most BUSY stores; longer numbers and decimals are refused with 400; since 2026-10-18 BUSY's read-back of 1,000 and more, shown with Indian grouping such as <code>12,34,567</code>, is compared by value); a date <code>\"YYYY-MM-DD\"</code>; Yes/No <code>true</code>/<code>false</code>. On a create, <code>null</code> is refused. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (<code>502 BUSY_WRITE_UNVERIFIED</code> names <code>optionalFields.OF</code>n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract <code>docs/LOCAL-API.md</code> 5an; guide <code>docs/public/api/optional-fields.md</code>.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n<h2 id=\"full-synthetic-optional-field-request-example-local-only\">FULL synthetic optional-field request example (Local only)</h2>\n<p>The raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check <code>/optional-field-definitions</code> before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, <code>null</code> clears OF1; omitted slots remain unchanged. On create, <code>null</code> is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Item 01\",\n  \"alias\": \"AZAPI-ITEM-01\",\n  \"parentGroup\": {\n    \"name\": \"General\"\n  },\n  \"mainUnit\": {\n    \"name\": \"Pcs.\"\n  },\n  \"salePrice\": 150,\n  \"purchasePrice\": 100,\n  \"mrp\": 200,\n  \"hsnCode\": \"84713010\",\n  \"descriptionLines\": [\n    \"Synthetic test item\"\n  ],\n  \"optionalFields\": {\n    \"OF1\": \"Synthetic shade\",\n    \"OF2\": 0,\n    \"OF3\": false\n  }\n}\n</code></pre>\n<p>Original destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","product-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"f5a3e2c7-77bb-7672-12eb-3dfbae456acc","name":"200 – product created and verified (synthetic example)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Item 01\",\n  \"alias\": \"AZAPI-ITEM-01\",\n  \"parentGroup\": { \"name\": \"General\" },\n  \"mainUnit\": { \"name\": \"Pcs.\" },\n  \"salePrice\": 150,\n  \"purchasePrice\": 100,\n  \"mrp\": 200,\n  \"hsnCode\": \"84713010\",\n  \"descriptionLines\": [\"Synthetic test item\"]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-create","description":"**Local** · `POST {{baseUrl}}/api/v1/product-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `name`, `parentGroup`, `mainUnit` · operation `busy.products.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). An `alternateUnit` needs BUSY's \"Alternate Unit of Items\" option (else `422 BUSY_SETTING_REQUIRED`, field `alternateUnit`; `502 BUSY_SETTINGS_UNREADABLE` when BUSY's configuration cannot be read).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.products.create` (`POST /api/v1/product-create`) creates one BUSY product (item) through BUSY's own COM component on this PC, then reads it back and checks every field you sent before answering. Never an upsert. Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Use only a **development-test company** (`targetCompanyCode`) and a **new, unique test name** (change `name` and `alias` before each send). Never a customer's company. Created test products stay in BUSY.\n- The example sends **no opening stock** on purpose (it is part of the books). Add it only on a test product, deliberately.\n- **Never retry a write blindly**: a second send of the same body is refused (`409 MASTER_NAME_TAKEN`) if the first saved; after `504 BUSY_WRITE_UNCERTAIN` look the product up (Products search) first.\n- References (`parentGroup`, `mainUnit`, `alternateUnit.unit`, `taxCategory`, `openingStock.materialCenter`) must exist in the company; a name more than one master shares is `422 MASTER_REFERENCE_AMBIGUOUS`.\n\n**Body:** `companyCode`, `financialYear`, `name` (1-40, required), `alias`, `printName` (1-60), `parentGroup` (required, item group `{\"code\": n}` or `{\"name\": \"…\"}`), `mainUnit` (required), `alternateUnit` (`{\"unit\": {\"name\": \"Dozen\"}, \"conversionFactor\": 12}`), `salePrice`, `purchasePrice`, `mrp` (≥ 0, ≤ 4 decimals), `salesDiscountPercent`, `purchaseDiscountPercent` (0-100), `hsnCode` (4-8 digits), `taxCategory` (e.g. `{\"name\": \"GST 18%\"}`; BUSY sets the rates from it), `descriptionLines` (1-4 lines of 1-40), `openingStock` (`{\"quantity\": 10, \"amount\": 1000, \"materialCenter\": {\"name\": \"Main Store\"}}`; one godown, conversion factor 1 only).\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }`; `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType (product), outcome (created), verifiedFields, elapsedMs, executedAt`. The test stores `masterProductId` / `masterProductName` for the modify request.\n\n**Errors:** as account create (400, 403, 404, 409 `MASTER_NAME_TAKEN` / `MASTER_WRITE_PROVIDER_UNSUPPORTED`, 422 references, 502 `BUSY_WRITE_FAILED` / `BUSY_WRITE_UNVERIFIED`, 503 `BUSY_COM_*`, 504 `BUSY_WRITE_UNCERTAIN` / `BUSY_COM_TIMEOUT`).\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Products: text; a dropdown as `{\"code\": n}` or `{\"name\": \"…\"}` of an **existing** value of that slot's own list (unknown `422 OPTIONAL_FIELD_VALUE_NOT_FOUND`: BUSY would add it silently — create it first with **⚠ BUSY product dropdown value – create**); a whole number from -999999999999 to 999999999999 (12 digits, the most BUSY stores; longer numbers and decimals are refused with 400; since 2026-10-18 BUSY's read-back of 1,000 and more, shown with Indian grouping such as `12,34,567`, is compared by value); a date `\"YYYY-MM-DD\"`; Yes/No `true`/`false`. On a create, `null` is refused. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\n\n## FULL synthetic optional-field request example (Local only)\nThe raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check `/optional-field-definitions` before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, `null` clears OF1; omitted slots remain unchanged. On create, `null` is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.\n```json\n{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Item 01\",\n  \"alias\": \"AZAPI-ITEM-01\",\n  \"parentGroup\": {\n    \"name\": \"General\"\n  },\n  \"mainUnit\": {\n    \"name\": \"Pcs.\"\n  },\n  \"salePrice\": 150,\n  \"purchasePrice\": 100,\n  \"mrp\": 200,\n  \"hsnCode\": \"84713010\",\n  \"descriptionLines\": [\n    \"Synthetic test item\"\n  ],\n  \"optionalFields\": {\n    \"OF1\": \"Synthetic shade\",\n    \"OF2\": 0,\n    \"OF3\": false\n  }\n}\n```\n\r\n\r\nOriginal destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e16"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"masterId\": 9401,\n    \"name\": \"AZAPI Test Item 01\",\n    \"alias\": \"AZAPI-ITEM-01\",\n    \"fields\": {\n      \"name\": \"AZAPI Test Item 01\",\n      \"alias\": \"AZAPI-ITEM-01\",\n      \"parentGroup\": { \"code\": 401, \"name\": \"General\" },\n      \"mainUnit\": { \"code\": 1180, \"name\": \"Pcs.\" },\n      \"salePrice\": 150,\n      \"purchasePrice\": 100,\n      \"mrp\": 200,\n      \"hsnCode\": \"84713010\",\n      \"descriptionLines\": [\"Synthetic test item\"]\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.products.create\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e16\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"masterType\": \"product\",\n    \"outcome\": \"created\",\n    \"verifiedFields\": [\"name\", \"alias\", \"parentGroup\", \"mainUnit\", \"salePrice\", \"purchasePrice\", \"mrp\", \"hsnCode\", \"descriptionLines\"],\n    \"elapsedMs\": 4020,\n    \"executedAt\": \"2026-09-26T10:00:00+00:00\"\n  }\n}"},{"id":"cb87255c-cbbf-ef53-c8ff-59fddf642602","name":"409 – Access company (MASTER_WRITE_PROVIDER_UNSUPPORTED)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Item 01\",\n  \"alias\": \"AZAPI-ITEM-01\",\n  \"parentGroup\": { \"name\": \"General\" },\n  \"mainUnit\": { \"name\": \"Pcs.\" },\n  \"salePrice\": 150,\n  \"purchasePrice\": 100,\n  \"mrp\": 200,\n  \"hsnCode\": \"84713010\",\n  \"descriptionLines\": [\"Synthetic test item\"]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-create","description":"**Local** · `POST {{baseUrl}}/api/v1/product-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `name`, `parentGroup`, `mainUnit` · operation `busy.products.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). An `alternateUnit` needs BUSY's \"Alternate Unit of Items\" option (else `422 BUSY_SETTING_REQUIRED`, field `alternateUnit`; `502 BUSY_SETTINGS_UNREADABLE` when BUSY's configuration cannot be read).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.products.create` (`POST /api/v1/product-create`) creates one BUSY product (item) through BUSY's own COM component on this PC, then reads it back and checks every field you sent before answering. Never an upsert. Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Use only a **development-test company** (`targetCompanyCode`) and a **new, unique test name** (change `name` and `alias` before each send). Never a customer's company. Created test products stay in BUSY.\n- The example sends **no opening stock** on purpose (it is part of the books). Add it only on a test product, deliberately.\n- **Never retry a write blindly**: a second send of the same body is refused (`409 MASTER_NAME_TAKEN`) if the first saved; after `504 BUSY_WRITE_UNCERTAIN` look the product up (Products search) first.\n- References (`parentGroup`, `mainUnit`, `alternateUnit.unit`, `taxCategory`, `openingStock.materialCenter`) must exist in the company; a name more than one master shares is `422 MASTER_REFERENCE_AMBIGUOUS`.\n\n**Body:** `companyCode`, `financialYear`, `name` (1-40, required), `alias`, `printName` (1-60), `parentGroup` (required, item group `{\"code\": n}` or `{\"name\": \"…\"}`), `mainUnit` (required), `alternateUnit` (`{\"unit\": {\"name\": \"Dozen\"}, \"conversionFactor\": 12}`), `salePrice`, `purchasePrice`, `mrp` (≥ 0, ≤ 4 decimals), `salesDiscountPercent`, `purchaseDiscountPercent` (0-100), `hsnCode` (4-8 digits), `taxCategory` (e.g. `{\"name\": \"GST 18%\"}`; BUSY sets the rates from it), `descriptionLines` (1-4 lines of 1-40), `openingStock` (`{\"quantity\": 10, \"amount\": 1000, \"materialCenter\": {\"name\": \"Main Store\"}}`; one godown, conversion factor 1 only).\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }`; `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType (product), outcome (created), verifiedFields, elapsedMs, executedAt`. The test stores `masterProductId` / `masterProductName` for the modify request.\n\n**Errors:** as account create (400, 403, 404, 409 `MASTER_NAME_TAKEN` / `MASTER_WRITE_PROVIDER_UNSUPPORTED`, 422 references, 502 `BUSY_WRITE_FAILED` / `BUSY_WRITE_UNVERIFIED`, 503 `BUSY_COM_*`, 504 `BUSY_WRITE_UNCERTAIN` / `BUSY_COM_TIMEOUT`).\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Products: text; a dropdown as `{\"code\": n}` or `{\"name\": \"…\"}` of an **existing** value of that slot's own list (unknown `422 OPTIONAL_FIELD_VALUE_NOT_FOUND`: BUSY would add it silently — create it first with **⚠ BUSY product dropdown value – create**); a whole number from -999999999999 to 999999999999 (12 digits, the most BUSY stores; longer numbers and decimals are refused with 400; since 2026-10-18 BUSY's read-back of 1,000 and more, shown with Indian grouping such as `12,34,567`, is compared by value); a date `\"YYYY-MM-DD\"`; Yes/No `true`/`false`. On a create, `null` is refused. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\n\n## FULL synthetic optional-field request example (Local only)\nThe raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check `/optional-field-definitions` before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, `null` clears OF1; omitted slots remain unchanged. On create, `null` is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.\n```json\n{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Item 01\",\n  \"alias\": \"AZAPI-ITEM-01\",\n  \"parentGroup\": {\n    \"name\": \"General\"\n  },\n  \"mainUnit\": {\n    \"name\": \"Pcs.\"\n  },\n  \"salePrice\": 150,\n  \"purchasePrice\": 100,\n  \"mrp\": 200,\n  \"hsnCode\": \"84713010\",\n  \"descriptionLines\": [\n    \"Synthetic test item\"\n  ],\n  \"optionalFields\": {\n    \"OF1\": \"Synthetic shade\",\n    \"OF2\": 0,\n    \"OF3\": false\n  }\n}\n```\n\r\n\r\nOriginal destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e18"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"MASTER_WRITE_PROVIDER_UNSUPPORTED\",\n      \"message\": \"Creating and changing BUSY masters is available for SQL Server companies only; it has not been tested on Access companies.\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e18\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"45210635-3f84-d096-22db-cc0d9c9560f0","name":"422 – group name shared by two item groups (MASTER_REFERENCE_AMBIGUOUS, current text)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Item 01\",\n  \"alias\": \"AZAPI-ITEM-01\",\n  \"parentGroup\": { \"name\": \"General\" },\n  \"mainUnit\": { \"name\": \"Pcs.\" },\n  \"salePrice\": 150,\n  \"purchasePrice\": 100,\n  \"mrp\": 200,\n  \"hsnCode\": \"84713010\",\n  \"descriptionLines\": [\"Synthetic test item\"]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-create","description":"**Local** · `POST {{baseUrl}}/api/v1/product-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `name`, `parentGroup`, `mainUnit` · operation `busy.products.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). An `alternateUnit` needs BUSY's \"Alternate Unit of Items\" option (else `422 BUSY_SETTING_REQUIRED`, field `alternateUnit`; `502 BUSY_SETTINGS_UNREADABLE` when BUSY's configuration cannot be read).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.products.create` (`POST /api/v1/product-create`) creates one BUSY product (item) through BUSY's own COM component on this PC, then reads it back and checks every field you sent before answering. Never an upsert. Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Use only a **development-test company** (`targetCompanyCode`) and a **new, unique test name** (change `name` and `alias` before each send). Never a customer's company. Created test products stay in BUSY.\n- The example sends **no opening stock** on purpose (it is part of the books). Add it only on a test product, deliberately.\n- **Never retry a write blindly**: a second send of the same body is refused (`409 MASTER_NAME_TAKEN`) if the first saved; after `504 BUSY_WRITE_UNCERTAIN` look the product up (Products search) first.\n- References (`parentGroup`, `mainUnit`, `alternateUnit.unit`, `taxCategory`, `openingStock.materialCenter`) must exist in the company; a name more than one master shares is `422 MASTER_REFERENCE_AMBIGUOUS`.\n\n**Body:** `companyCode`, `financialYear`, `name` (1-40, required), `alias`, `printName` (1-60), `parentGroup` (required, item group `{\"code\": n}` or `{\"name\": \"…\"}`), `mainUnit` (required), `alternateUnit` (`{\"unit\": {\"name\": \"Dozen\"}, \"conversionFactor\": 12}`), `salePrice`, `purchasePrice`, `mrp` (≥ 0, ≤ 4 decimals), `salesDiscountPercent`, `purchaseDiscountPercent` (0-100), `hsnCode` (4-8 digits), `taxCategory` (e.g. `{\"name\": \"GST 18%\"}`; BUSY sets the rates from it), `descriptionLines` (1-4 lines of 1-40), `openingStock` (`{\"quantity\": 10, \"amount\": 1000, \"materialCenter\": {\"name\": \"Main Store\"}}`; one godown, conversion factor 1 only).\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }`; `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType (product), outcome (created), verifiedFields, elapsedMs, executedAt`. The test stores `masterProductId` / `masterProductName` for the modify request.\n\n**Errors:** as account create (400, 403, 404, 409 `MASTER_NAME_TAKEN` / `MASTER_WRITE_PROVIDER_UNSUPPORTED`, 422 references, 502 `BUSY_WRITE_FAILED` / `BUSY_WRITE_UNVERIFIED`, 503 `BUSY_COM_*`, 504 `BUSY_WRITE_UNCERTAIN` / `BUSY_COM_TIMEOUT`).\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Products: text; a dropdown as `{\"code\": n}` or `{\"name\": \"…\"}` of an **existing** value of that slot's own list (unknown `422 OPTIONAL_FIELD_VALUE_NOT_FOUND`: BUSY would add it silently — create it first with **⚠ BUSY product dropdown value – create**); a whole number from -999999999999 to 999999999999 (12 digits, the most BUSY stores; longer numbers and decimals are refused with 400; since 2026-10-18 BUSY's read-back of 1,000 and more, shown with Indian grouping such as `12,34,567`, is compared by value); a date `\"YYYY-MM-DD\"`; Yes/No `true`/`false`. On a create, `null` is refused. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\n\n## FULL synthetic optional-field request example (Local only)\nThe raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check `/optional-field-definitions` before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, `null` clears OF1; omitted slots remain unchanged. On create, `null` is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.\n```json\n{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Item 01\",\n  \"alias\": \"AZAPI-ITEM-01\",\n  \"parentGroup\": {\n    \"name\": \"General\"\n  },\n  \"mainUnit\": {\n    \"name\": \"Pcs.\"\n  },\n  \"salePrice\": 150,\n  \"purchasePrice\": 100,\n  \"mrp\": 200,\n  \"hsnCode\": \"84713010\",\n  \"descriptionLines\": [\n    \"Synthetic test item\"\n  ],\n  \"optionalFields\": {\n    \"OF1\": \"Synthetic shade\",\n    \"OF2\": 0,\n    \"OF3\": false\n  }\n}\n```\n\r\n\r\nOriginal destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e19","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"MASTER_REFERENCE_AMBIGUOUS\",\n      \"message\": \"More than one item group has that name in BUSY. BUSY refers to it by its name, so it cannot be chosen here; give it a distinct name in BUSY first.\",\n      \"field\": \"parentGroup\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e19\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"2fb2ebde-a4c6-2250-4b52-8383a41ca8ec","name":"409 – optional-field configuration changed (no write)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Item 01\",\n  \"alias\": \"AZAPI-ITEM-01\",\n  \"parentGroup\": {\n    \"name\": \"General\"\n  },\n  \"mainUnit\": {\n    \"name\": \"Pcs.\"\n  },\n  \"salePrice\": 150,\n  \"purchasePrice\": 100,\n  \"mrp\": 200,\n  \"hsnCode\": \"84713010\",\n  \"descriptionLines\": [\n    \"Synthetic test item\"\n  ],\n  \"optionalFields\": {\n    \"OF1\": \"Synthetic value\"\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-create","description":"**Local** · `POST {{baseUrl}}/api/v1/product-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `name`, `parentGroup`, `mainUnit` · operation `busy.products.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). An `alternateUnit` needs BUSY's \"Alternate Unit of Items\" option (else `422 BUSY_SETTING_REQUIRED`, field `alternateUnit`; `502 BUSY_SETTINGS_UNREADABLE` when BUSY's configuration cannot be read).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.products.create` (`POST /api/v1/product-create`) creates one BUSY product (item) through BUSY's own COM component on this PC, then reads it back and checks every field you sent before answering. Never an upsert. Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Use only a **development-test company** (`targetCompanyCode`) and a **new, unique test name** (change `name` and `alias` before each send). Never a customer's company. Created test products stay in BUSY.\n- The example sends **no opening stock** on purpose (it is part of the books). Add it only on a test product, deliberately.\n- **Never retry a write blindly**: a second send of the same body is refused (`409 MASTER_NAME_TAKEN`) if the first saved; after `504 BUSY_WRITE_UNCERTAIN` look the product up (Products search) first.\n- References (`parentGroup`, `mainUnit`, `alternateUnit.unit`, `taxCategory`, `openingStock.materialCenter`) must exist in the company; a name more than one master shares is `422 MASTER_REFERENCE_AMBIGUOUS`.\n\n**Body:** `companyCode`, `financialYear`, `name` (1-40, required), `alias`, `printName` (1-60), `parentGroup` (required, item group `{\"code\": n}` or `{\"name\": \"…\"}`), `mainUnit` (required), `alternateUnit` (`{\"unit\": {\"name\": \"Dozen\"}, \"conversionFactor\": 12}`), `salePrice`, `purchasePrice`, `mrp` (≥ 0, ≤ 4 decimals), `salesDiscountPercent`, `purchaseDiscountPercent` (0-100), `hsnCode` (4-8 digits), `taxCategory` (e.g. `{\"name\": \"GST 18%\"}`; BUSY sets the rates from it), `descriptionLines` (1-4 lines of 1-40), `openingStock` (`{\"quantity\": 10, \"amount\": 1000, \"materialCenter\": {\"name\": \"Main Store\"}}`; one godown, conversion factor 1 only).\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }`; `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType (product), outcome (created), verifiedFields, elapsedMs, executedAt`. The test stores `masterProductId` / `masterProductName` for the modify request.\n\n**Errors:** as account create (400, 403, 404, 409 `MASTER_NAME_TAKEN` / `MASTER_WRITE_PROVIDER_UNSUPPORTED`, 422 references, 502 `BUSY_WRITE_FAILED` / `BUSY_WRITE_UNVERIFIED`, 503 `BUSY_COM_*`, 504 `BUSY_WRITE_UNCERTAIN` / `BUSY_COM_TIMEOUT`).\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Products: text; a dropdown as `{\"code\": n}` or `{\"name\": \"…\"}` of an **existing** value of that slot's own list (unknown `422 OPTIONAL_FIELD_VALUE_NOT_FOUND`: BUSY would add it silently — create it first with **⚠ BUSY product dropdown value – create**); a whole number from -999999999999 to 999999999999 (12 digits, the most BUSY stores; longer numbers and decimals are refused with 400; since 2026-10-18 BUSY's read-back of 1,000 and more, shown with Indian grouping such as `12,34,567`, is compared by value); a date `\"YYYY-MM-DD\"`; Yes/No `true`/`false`. On a create, `null` is refused. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"OPTIONAL_FIELD_CONFIGURATION_CHANGED\",\n      \"message\": \"BUSY's optional-field configuration changed while this master write was being prepared. Nothing was written. Read the definitions and prepare a new request.\",\n      \"field\": \"optionalFields\"\n    },\n    \"requestId\": \"00000000000000000000000000000001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"9d2275c1-83bc-5707-edb4-e59e066b1b6c","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Item 01\",\n  \"alias\": \"AZAPI-ITEM-01\",\n  \"parentGroup\": {\n    \"name\": \"General\"\n  },\n  \"mainUnit\": {\n    \"name\": \"Pcs.\"\n  },\n  \"salePrice\": 150,\n  \"purchasePrice\": 100,\n  \"mrp\": 200,\n  \"hsnCode\": \"84713010\",\n  \"descriptionLines\": [\n    \"Synthetic test item\"\n  ],\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-create"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"},{"value":"synthetic-queue-001","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.products.create\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"},{"id":"94d86035-f6a5-4201-afd4-c64b43e5112e","name":"409 - BUSY_WRITE_TARGET_CHANGED (synthetic; before save)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/product-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"BUSY_WRITE_TARGET_CHANGED\",\"message\":\"The BUSY destination or its permissions changed before helper execution; nothing was saved.\"}}}"},{"id":"32384029-4156-4592-90d7-1d749d9c05be","name":"409 - MASTER_REFERENCE_CHANGED (synthetic; before save)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/product-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"MASTER_REFERENCE_CHANGED\",\"message\":\"An ordinary master reference changed before the save; nothing was saved. Read the references again.\"}}}"}],"_postman_id":"941c11bd-e159-9efe-4787-ed47a1d7ddaa"},{"name":"⚠ BUSY master – modify product (writes to BUSY)","id":"ec288298-96c0-0cb7-c777-577743dacb88","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": {{masterProductId}},\n  \"expectedName\": \"{{masterProductName}}\",\n  \"salePrice\": 160,\n  \"mrp\": 210\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-modify","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/product-modify</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>)\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>productId</code> · operation <code>busy.products.modify</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books. Run manually, one at a time.</strong> <code>busy.products.modify</code> (<code>POST /api/v1/product-modify</code>) changes only the fields you send of one existing BUSY product, named by BUSY's code (<code>productId</code> = <code>product_id</code> in the product operations). BUSY's own record is read, edited and saved; every other field stays as it is, and the record is compared before and after. Not relayed by the current Windows build (the cloud route exists since cloud <code>3b13ab1</code>, but this PC refuses relayed writes: see Cloud → ⚠ Master Create &amp; Modify); never run from scripts.</p>\n<p><strong>Safe test guidance</strong></p>\n<ul>\n<li>Change <strong>only a test product you created yourself</strong> — the create request stores <code>masterProductId</code> and <code>masterProductName</code>. Never a customer's product. The pre-request script skips the request when either variable is empty.</li>\n<li>Always send <code>expectedName</code> (nothing is changed when it differs: <code>409 MASTER_NAME_MISMATCH</code>).</li>\n<li><strong>Never retry a write blindly.</strong> After <code>504 BUSY_WRITE_UNCERTAIN</code>, read the product first and compare.</li>\n</ul>\n<p><strong>Changeable:</strong> <code>printName</code>, <code>salePrice</code>, <code>purchasePrice</code>, <code>mrp</code>, <code>salesDiscountPercent</code>, <code>purchaseDiscountPercent</code>, <code>hsnCode</code>, <code>taxCategory</code>, <code>descriptionLines</code> (lines not sent keep their text), and <code>openingStock</code> (<code>{quantity, amount, materialCenter}</code>) <strong>only</strong> in the one godown the product's opening stock is already in, with a conversion factor of 1 (otherwise <code>409 MASTER_CHANGE_UNSUPPORTED</code>). <strong>Not changeable here:</strong> name, alias, group, units.</p>\n<p><strong>Answer (200):</strong> <code>data</code> = <code>{ masterId, name, alias, fields }</code> (only the fields sent); <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, masterType (product), outcome (modified), verifiedFields, elapsedMs, executedAt</code>.</p>\n<p><strong>Errors:</strong> as product create, plus 404 <code>NOT_FOUND</code> (<code>field: productId</code>), 409 <code>MASTER_TYPE_MISMATCH</code> (the code is not a product), <code>MASTER_NAME_MISMATCH</code>, <code>MASTER_CHANGE_UNSUPPORTED</code>.</p>\n<p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5ab.</p>\n<p><strong>Optional fields (since 2026-10-17):</strong> optional member <code>optionalFields</code>. Keyed <code>OF1</code>–<code>OF10</code> (read the slots with <strong>busy.optional-fields.definitions</strong> for the same year first); the slot must be defined for this master type in that year (<code>422 OPTIONAL_FIELD_NOT_DEFINED</code>). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Products: text; a dropdown as <code>{\"code\": n}</code> or <code>{\"name\": \"…\"}</code> of an <strong>existing</strong> value of that slot's own list (unknown <code>422 OPTIONAL_FIELD_VALUE_NOT_FOUND</code>: BUSY would add it silently — create it first with <strong>⚠ BUSY product dropdown value – create</strong>); a whole number from -999999999999 to 999999999999 (12 digits, the most BUSY stores; longer numbers and decimals are refused with 400; since 2026-10-18 BUSY's read-back of 1,000 and more, shown with Indian grouping such as <code>12,34,567</code>, is compared by value); a date <code>\"YYYY-MM-DD\"</code>; Yes/No <code>true</code>/<code>false</code>. On a modify, omitted slots keep their values, <code>null</code> clears a slot, an empty string is refused; only the slot elements of BUSY's own record are edited. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (<code>502 BUSY_WRITE_UNVERIFIED</code> names <code>optionalFields.OF</code>n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract <code>docs/LOCAL-API.md</code> 5an; guide <code>docs/public/api/optional-fields.md</code>.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n<h2 id=\"full-synthetic-optional-field-request-example-local-only\">FULL synthetic optional-field request example (Local only)</h2>\n<p>The raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check <code>/optional-field-definitions</code> before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, <code>null</code> clears OF1; omitted slots remain unchanged. On create, <code>null</code> is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": \"{{masterProductId}}\",\n  \"expectedName\": \"{{masterProductName}}\",\n  \"salePrice\": 160,\n  \"mrp\": 210,\n  \"optionalFields\": {\n    \"OF1\": null,\n    \"OF2\": 0,\n    \"OF3\": false\n  }\n}\n</code></pre>\n<p>Original destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","product-modify"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"abc80426-21eb-5046-0e22-47b15dd9c266","name":"200 – product modified and verified (synthetic example)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": {{masterProductId}},\n  \"expectedName\": \"{{masterProductName}}\",\n  \"salePrice\": 160,\n  \"mrp\": 210\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/product-modify` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `productId` · operation `busy.products.modify`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.products.modify` (`POST /api/v1/product-modify`) changes only the fields you send of one existing BUSY product, named by BUSY's code (`productId` = `product_id` in the product operations). BUSY's own record is read, edited and saved; every other field stays as it is, and the record is compared before and after. Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Change **only a test product you created yourself** — the create request stores `masterProductId` and `masterProductName`. Never a customer's product. The pre-request script skips the request when either variable is empty.\n- Always send `expectedName` (nothing is changed when it differs: `409 MASTER_NAME_MISMATCH`).\n- **Never retry a write blindly.** After `504 BUSY_WRITE_UNCERTAIN`, read the product first and compare.\n\n**Changeable:** `printName`, `salePrice`, `purchasePrice`, `mrp`, `salesDiscountPercent`, `purchaseDiscountPercent`, `hsnCode`, `taxCategory`, `descriptionLines` (lines not sent keep their text), and `openingStock` (`{quantity, amount, materialCenter}`) **only** in the one godown the product's opening stock is already in, with a conversion factor of 1 (otherwise `409 MASTER_CHANGE_UNSUPPORTED`). **Not changeable here:** name, alias, group, units.\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }` (only the fields sent); `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType (product), outcome (modified), verifiedFields, elapsedMs, executedAt`.\n\n**Errors:** as product create, plus 404 `NOT_FOUND` (`field: productId`), 409 `MASTER_TYPE_MISMATCH` (the code is not a product), `MASTER_NAME_MISMATCH`, `MASTER_CHANGE_UNSUPPORTED`.\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Products: text; a dropdown as `{\"code\": n}` or `{\"name\": \"…\"}` of an **existing** value of that slot's own list (unknown `422 OPTIONAL_FIELD_VALUE_NOT_FOUND`: BUSY would add it silently — create it first with **⚠ BUSY product dropdown value – create**); a whole number from -999999999999 to 999999999999 (12 digits, the most BUSY stores; longer numbers and decimals are refused with 400; since 2026-10-18 BUSY's read-back of 1,000 and more, shown with Indian grouping such as `12,34,567`, is compared by value); a date `\"YYYY-MM-DD\"`; Yes/No `true`/`false`. On a modify, omitted slots keep their values, `null` clears a slot, an empty string is refused; only the slot elements of BUSY's own record are edited. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\n\n## FULL synthetic optional-field request example (Local only)\nThe raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check `/optional-field-definitions` before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, `null` clears OF1; omitted slots remain unchanged. On create, `null` is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.\n```json\n{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": \"{{masterProductId}}\",\n  \"expectedName\": \"{{masterProductName}}\",\n  \"salePrice\": 160,\n  \"mrp\": 210,\n  \"optionalFields\": {\n    \"OF1\": null,\n    \"OF2\": 0,\n    \"OF3\": false\n  }\n}\n```\n\r\n\r\nOriginal destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e20","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"masterId\": 9401,\n    \"name\": \"AZAPI Test Item 01\",\n    \"alias\": \"AZAPI-ITEM-01\",\n    \"fields\": {\n      \"salePrice\": 160,\n      \"mrp\": 210\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.products.modify\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e20\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"masterType\": \"product\",\n    \"outcome\": \"modified\",\n    \"verifiedFields\": [\"salePrice\", \"mrp\"],\n    \"elapsedMs\": 3770,\n    \"executedAt\": \"2026-09-26T10:00:00+00:00\"\n  }\n}"},{"id":"0cb742b0-c4e4-3b29-6eeb-21caa0d3ff65","name":"502 – saved but read-back differs (BUSY_WRITE_UNVERIFIED; check in BUSY)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": {{masterProductId}},\n  \"expectedName\": \"{{masterProductName}}\",\n  \"salePrice\": 160,\n  \"mrp\": 210\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/product-modify` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `productId` · operation `busy.products.modify`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.products.modify` (`POST /api/v1/product-modify`) changes only the fields you send of one existing BUSY product, named by BUSY's code (`productId` = `product_id` in the product operations). BUSY's own record is read, edited and saved; every other field stays as it is, and the record is compared before and after. Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Change **only a test product you created yourself** — the create request stores `masterProductId` and `masterProductName`. Never a customer's product. The pre-request script skips the request when either variable is empty.\n- Always send `expectedName` (nothing is changed when it differs: `409 MASTER_NAME_MISMATCH`).\n- **Never retry a write blindly.** After `504 BUSY_WRITE_UNCERTAIN`, read the product first and compare.\n\n**Changeable:** `printName`, `salePrice`, `purchasePrice`, `mrp`, `salesDiscountPercent`, `purchaseDiscountPercent`, `hsnCode`, `taxCategory`, `descriptionLines` (lines not sent keep their text), and `openingStock` (`{quantity, amount, materialCenter}`) **only** in the one godown the product's opening stock is already in, with a conversion factor of 1 (otherwise `409 MASTER_CHANGE_UNSUPPORTED`). **Not changeable here:** name, alias, group, units.\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }` (only the fields sent); `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType (product), outcome (modified), verifiedFields, elapsedMs, executedAt`.\n\n**Errors:** as product create, plus 404 `NOT_FOUND` (`field: productId`), 409 `MASTER_TYPE_MISMATCH` (the code is not a product), `MASTER_NAME_MISMATCH`, `MASTER_CHANGE_UNSUPPORTED`.\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Products: text; a dropdown as `{\"code\": n}` or `{\"name\": \"…\"}` of an **existing** value of that slot's own list (unknown `422 OPTIONAL_FIELD_VALUE_NOT_FOUND`: BUSY would add it silently — create it first with **⚠ BUSY product dropdown value – create**); a whole number from -999999999999 to 999999999999 (12 digits, the most BUSY stores; longer numbers and decimals are refused with 400; since 2026-10-18 BUSY's read-back of 1,000 and more, shown with Indian grouping such as `12,34,567`, is compared by value); a date `\"YYYY-MM-DD\"`; Yes/No `true`/`false`. On a modify, omitted slots keep their values, `null` clears a slot, an empty string is refused; only the slot elements of BUSY's own record are edited. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\n\n## FULL synthetic optional-field request example (Local only)\nThe raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check `/optional-field-definitions` before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, `null` clears OF1; omitted slots remain unchanged. On create, `null` is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.\n```json\n{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": \"{{masterProductId}}\",\n  \"expectedName\": \"{{masterProductName}}\",\n  \"salePrice\": 160,\n  \"mrp\": 210,\n  \"optionalFields\": {\n    \"OF1\": null,\n    \"OF2\": 0,\n    \"OF3\": false\n  }\n}\n```\n\r\n\r\nOriginal destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes."},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e21","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNVERIFIED\",\n      \"message\": \"BUSY saved the master, but its read-back differs from the request in the fields listed in metadata.error.details.mismatchedFields. The change is in BUSY; check it there.\",\n      \"details\": {\n        \"masterId\": 9401,\n        \"mismatchedFields\": [\"mrp\"]\n      }\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e21\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"8e7a28ab-1a56-66e0-31d1-dad4acddd273","name":"404 – no master with that productId (NOT_FOUND)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": {{masterProductId}},\n  \"expectedName\": \"{{masterProductName}}\",\n  \"salePrice\": 160,\n  \"mrp\": 210\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/product-modify` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `productId` · operation `busy.products.modify`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.products.modify` (`POST /api/v1/product-modify`) changes only the fields you send of one existing BUSY product, named by BUSY's code (`productId` = `product_id` in the product operations). BUSY's own record is read, edited and saved; every other field stays as it is, and the record is compared before and after. Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Change **only a test product you created yourself** — the create request stores `masterProductId` and `masterProductName`. Never a customer's product. The pre-request script skips the request when either variable is empty.\n- Always send `expectedName` (nothing is changed when it differs: `409 MASTER_NAME_MISMATCH`).\n- **Never retry a write blindly.** After `504 BUSY_WRITE_UNCERTAIN`, read the product first and compare.\n\n**Changeable:** `printName`, `salePrice`, `purchasePrice`, `mrp`, `salesDiscountPercent`, `purchaseDiscountPercent`, `hsnCode`, `taxCategory`, `descriptionLines` (lines not sent keep their text), and `openingStock` (`{quantity, amount, materialCenter}`) **only** in the one godown the product's opening stock is already in, with a conversion factor of 1 (otherwise `409 MASTER_CHANGE_UNSUPPORTED`). **Not changeable here:** name, alias, group, units.\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }` (only the fields sent); `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType (product), outcome (modified), verifiedFields, elapsedMs, executedAt`.\n\n**Errors:** as product create, plus 404 `NOT_FOUND` (`field: productId`), 409 `MASTER_TYPE_MISMATCH` (the code is not a product), `MASTER_NAME_MISMATCH`, `MASTER_CHANGE_UNSUPPORTED`.\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Products: text; a dropdown as `{\"code\": n}` or `{\"name\": \"…\"}` of an **existing** value of that slot's own list (unknown `422 OPTIONAL_FIELD_VALUE_NOT_FOUND`: BUSY would add it silently — create it first with **⚠ BUSY product dropdown value – create**); a whole number from -999999999999 to 999999999999 (12 digits, the most BUSY stores; longer numbers and decimals are refused with 400; since 2026-10-18 BUSY's read-back of 1,000 and more, shown with Indian grouping such as `12,34,567`, is compared by value); a date `\"YYYY-MM-DD\"`; Yes/No `true`/`false`. On a modify, omitted slots keep their values, `null` clears a slot, an empty string is refused; only the slot elements of BUSY's own record are edited. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\n\n## FULL synthetic optional-field request example (Local only)\nThe raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check `/optional-field-definitions` before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, `null` clears OF1; omitted slots remain unchanged. On create, `null` is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.\n```json\n{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": \"{{masterProductId}}\",\n  \"expectedName\": \"{{masterProductName}}\",\n  \"salePrice\": 160,\n  \"mrp\": 210,\n  \"optionalFields\": {\n    \"OF1\": null,\n    \"OF2\": 0,\n    \"OF3\": false\n  }\n}\n```\n\r\n\r\nOriginal destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e22"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"NOT_FOUND\",\n      \"message\": \"No master with that productId exists in this company and financial year.\",\n      \"field\": \"productId\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e22\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"df478990-8ea1-115d-cdbc-b9b4b1a04dcd","name":"200 – optional fields set and one cleared (synthetic example)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": {{masterProductId}},\n  \"expectedName\": \"{{masterProductName}}\",\n  \"salePrice\": 160,\n  \"mrp\": 210\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/product-modify` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `productId` · operation `busy.products.modify`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.products.modify` (`POST /api/v1/product-modify`) changes only the fields you send of one existing BUSY product, named by BUSY's code (`productId` = `product_id` in the product operations). BUSY's own record is read, edited and saved; every other field stays as it is, and the record is compared before and after. Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Change **only a test product you created yourself** — the create request stores `masterProductId` and `masterProductName`. Never a customer's product. The pre-request script skips the request when either variable is empty.\n- Always send `expectedName` (nothing is changed when it differs: `409 MASTER_NAME_MISMATCH`).\n- **Never retry a write blindly.** After `504 BUSY_WRITE_UNCERTAIN`, read the product first and compare.\n\n**Changeable:** `printName`, `salePrice`, `purchasePrice`, `mrp`, `salesDiscountPercent`, `purchaseDiscountPercent`, `hsnCode`, `taxCategory`, `descriptionLines` (lines not sent keep their text), and `openingStock` (`{quantity, amount, materialCenter}`) **only** in the one godown the product's opening stock is already in, with a conversion factor of 1 (otherwise `409 MASTER_CHANGE_UNSUPPORTED`). **Not changeable here:** name, alias, group, units.\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }` (only the fields sent); `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType (product), outcome (modified), verifiedFields, elapsedMs, executedAt`.\n\n**Errors:** as product create, plus 404 `NOT_FOUND` (`field: productId`), 409 `MASTER_TYPE_MISMATCH` (the code is not a product), `MASTER_NAME_MISMATCH`, `MASTER_CHANGE_UNSUPPORTED`.\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Products: text; a dropdown as `{\"code\": n}` or `{\"name\": \"…\"}` of an **existing** value of that slot's own list (unknown `422 OPTIONAL_FIELD_VALUE_NOT_FOUND`: BUSY would add it silently — create it first with **⚠ BUSY product dropdown value – create**); a whole number from -999999999999 to 999999999999 (12 digits, the most BUSY stores; longer numbers and decimals are refused with 400; since 2026-10-18 BUSY's read-back of 1,000 and more, shown with Indian grouping such as `12,34,567`, is compared by value); a date `\"YYYY-MM-DD\"`; Yes/No `true`/`false`. On a modify, omitted slots keep their values, `null` clears a slot, an empty string is refused; only the slot elements of BUSY's own record are edited. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\n\n## FULL synthetic optional-field request example (Local only)\nThe raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check `/optional-field-definitions` before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, `null` clears OF1; omitted slots remain unchanged. On create, `null` is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.\n```json\n{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": \"{{masterProductId}}\",\n  \"expectedName\": \"{{masterProductName}}\",\n  \"salePrice\": 160,\n  \"mrp\": 210,\n  \"optionalFields\": {\n    \"OF1\": null,\n    \"OF2\": 0,\n    \"OF3\": false\n  }\n}\n```\n\r\n\r\nOriginal destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"masterId\": 7101,\n    \"name\": \"AZAPI Test Item 01\",\n    \"alias\": \"AZAPI-ITEM-01\",\n    \"fields\": {\n      \"optionalFields\": {\n        \"OF1\": { \"code\": 7311, \"name\": \"Synthetic Acme\" },\n        \"OF2\": \"Synthetic shade\",\n        \"OF3\": 12,\n        \"OF4\": \"2026-10-17\",\n        \"OF5\": null\n      }\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.products.modify\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e25\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"masterType\": \"product\",\n    \"outcome\": \"modified\",\n    \"verifiedFields\": [ \"optionalFields.OF1\", \"optionalFields.OF2\", \"optionalFields.OF3\", \"optionalFields.OF4\", \"optionalFields.OF5\" ],\n    \"elapsedMs\": 5310,\n    \"executedAt\": \"2026-10-17T12:00:00+00:00\"\n  }\n}"},{"id":"63d656e4-5b6f-77b8-5177-c3d13b445ab3","name":"422 – unknown dropdown value (OPTIONAL_FIELD_VALUE_NOT_FOUND; nothing written, no value created)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": {{masterProductId}},\n  \"expectedName\": \"{{masterProductName}}\",\n  \"salePrice\": 160,\n  \"mrp\": 210\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/product-modify` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `productId` · operation `busy.products.modify`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.products.modify` (`POST /api/v1/product-modify`) changes only the fields you send of one existing BUSY product, named by BUSY's code (`productId` = `product_id` in the product operations). BUSY's own record is read, edited and saved; every other field stays as it is, and the record is compared before and after. Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Change **only a test product you created yourself** — the create request stores `masterProductId` and `masterProductName`. Never a customer's product. The pre-request script skips the request when either variable is empty.\n- Always send `expectedName` (nothing is changed when it differs: `409 MASTER_NAME_MISMATCH`).\n- **Never retry a write blindly.** After `504 BUSY_WRITE_UNCERTAIN`, read the product first and compare.\n\n**Changeable:** `printName`, `salePrice`, `purchasePrice`, `mrp`, `salesDiscountPercent`, `purchaseDiscountPercent`, `hsnCode`, `taxCategory`, `descriptionLines` (lines not sent keep their text), and `openingStock` (`{quantity, amount, materialCenter}`) **only** in the one godown the product's opening stock is already in, with a conversion factor of 1 (otherwise `409 MASTER_CHANGE_UNSUPPORTED`). **Not changeable here:** name, alias, group, units.\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }` (only the fields sent); `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType (product), outcome (modified), verifiedFields, elapsedMs, executedAt`.\n\n**Errors:** as product create, plus 404 `NOT_FOUND` (`field: productId`), 409 `MASTER_TYPE_MISMATCH` (the code is not a product), `MASTER_NAME_MISMATCH`, `MASTER_CHANGE_UNSUPPORTED`.\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Products: text; a dropdown as `{\"code\": n}` or `{\"name\": \"…\"}` of an **existing** value of that slot's own list (unknown `422 OPTIONAL_FIELD_VALUE_NOT_FOUND`: BUSY would add it silently — create it first with **⚠ BUSY product dropdown value – create**); a whole number from -999999999999 to 999999999999 (12 digits, the most BUSY stores; longer numbers and decimals are refused with 400; since 2026-10-18 BUSY's read-back of 1,000 and more, shown with Indian grouping such as `12,34,567`, is compared by value); a date `\"YYYY-MM-DD\"`; Yes/No `true`/`false`. On a modify, omitted slots keep their values, `null` clears a slot, an empty string is refused; only the slot elements of BUSY's own record are edited. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\n\n## FULL synthetic optional-field request example (Local only)\nThe raw Body tab above remains the minimal request. This separate complete example is valid only for a company/FY where the relevant Account/Product definitions match these slots: OF1 free text; for Product, OF2 zero-decimal Number and OF3 Yes/No. Check `/optional-field-definitions` before sending; slot kinds and names are dynamic. Access Accounts may support other kinds, but SQL Server Accounts currently allow free text only. On modify, `null` clears OF1; omitted slots remain unchanged. On create, `null` is not accepted. Zero and false are values, not omission. Use a fresh synthetic master or an existing synthetic ID/name as applicable. Cloud Relay support is not implied.\n```json\n{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": \"{{masterProductId}}\",\n  \"expectedName\": \"{{masterProductName}}\",\n  \"salePrice\": 160,\n  \"mrp\": 210,\n  \"optionalFields\": {\n    \"OF1\": null,\n    \"OF2\": 0,\n    \"OF3\": false\n  }\n}\n```\n\r\n\r\nOriginal destination and master dependencies: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof. 409 MASTER_REFERENCE_CHANGED means an ordinary account/product parent-group, unit or tax-category identity changed before native save; re-read the named dependency and prepare a new request. It is distinct from optional-field dropdown identity changes."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"OPTIONAL_FIELD_VALUE_NOT_FOUND\",\n      \"message\": \"This dropdown has no such value in this financial year. A master write never creates one (BUSY would do so silently): create it first with POST /api/v1/product-optional-field-value-create, or choose an existing value. Nothing was written.\",\n      \"field\": \"optionalFields.OF1\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e26\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"a57e3da3-e742-0e51-d5f6-f0d5fd2f9479","name":"409 – optional-field configuration changed (no write)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP0001\",\n  \"financialYear\": \"2026\",\n  \"productId\": 1234,\n  \"expectedName\": \"Synthetic Product\",\n  \"optionalFields\": {\n    \"OF1\": \"Synthetic value\"\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/product-modify` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `productId` · operation `busy.products.modify`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.products.modify` (`POST /api/v1/product-modify`) changes only the fields you send of one existing BUSY product, named by BUSY's code (`productId` = `product_id` in the product operations). BUSY's own record is read, edited and saved; every other field stays as it is, and the record is compared before and after. Not relayed by the current Windows build (the cloud route exists since cloud `3b13ab1`, but this PC refuses relayed writes: see Cloud → ⚠ Master Create & Modify); never run from scripts.\n\n**Safe test guidance**\n- Change **only a test product you created yourself** — the create request stores `masterProductId` and `masterProductName`. Never a customer's product. The pre-request script skips the request when either variable is empty.\n- Always send `expectedName` (nothing is changed when it differs: `409 MASTER_NAME_MISMATCH`).\n- **Never retry a write blindly.** After `504 BUSY_WRITE_UNCERTAIN`, read the product first and compare.\n\n**Changeable:** `printName`, `salePrice`, `purchasePrice`, `mrp`, `salesDiscountPercent`, `purchaseDiscountPercent`, `hsnCode`, `taxCategory`, `descriptionLines` (lines not sent keep their text), and `openingStock` (`{quantity, amount, materialCenter}`) **only** in the one godown the product's opening stock is already in, with a conversion factor of 1 (otherwise `409 MASTER_CHANGE_UNSUPPORTED`). **Not changeable here:** name, alias, group, units.\n\n**Answer (200):** `data` = `{ masterId, name, alias, fields }` (only the fields sent); `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, masterType (product), outcome (modified), verifiedFields, elapsedMs, executedAt`.\n\n**Errors:** as product create, plus 404 `NOT_FOUND` (`field: productId`), 409 `MASTER_TYPE_MISMATCH` (the code is not a product), `MASTER_NAME_MISMATCH`, `MASTER_CHANGE_UNSUPPORTED`.\n\nGuard: skipped unless `confirmMutating` = `yes`. Canonical contract: `docs/LOCAL-API.md` section 5ab.\n\n**Optional fields (since 2026-10-17):** optional member `optionalFields`. Keyed `OF1`–`OF10` (read the slots with **busy.optional-fields.definitions** for the same year first); the slot must be defined for this master type in that year (`422 OPTIONAL_FIELD_NOT_DEFINED`). Text: 1–255 Latin-1 characters, no surrounding spaces (Hindi, emoji and other characters BUSY cannot store are refused, never stripped). Products: text; a dropdown as `{\"code\": n}` or `{\"name\": \"…\"}` of an **existing** value of that slot's own list (unknown `422 OPTIONAL_FIELD_VALUE_NOT_FOUND`: BUSY would add it silently — create it first with **⚠ BUSY product dropdown value – create**); a whole number from -999999999999 to 999999999999 (12 digits, the most BUSY stores; longer numbers and decimals are refused with 400; since 2026-10-18 BUSY's read-back of 1,000 and more, shown with Indian grouping such as `12,34,567`, is compared by value); a date `\"YYYY-MM-DD\"`; Yes/No `true`/`false`. On a modify, omitted slots keep their values, `null` clears a slot, an empty string is refused; only the slot elements of BUSY's own record are edited. After the save all ten stored slots and the dropdown lists are compared with independent read-only SQL (`502 BUSY_WRITE_UNVERIFIED` names `optionalFields.OF`n). Not offered: field-definition creation; account dropdown values on SQL Server companies. Contract `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"OPTIONAL_FIELD_CONFIGURATION_CHANGED\",\n      \"message\": \"BUSY's optional-field configuration changed while this master write was being prepared. Nothing was written. Read the definitions and prepare a new request.\",\n      \"field\": \"optionalFields\"\n    },\n    \"requestId\": \"00000000000000000000000000000001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"483aedfd-8d2f-647c-f0ea-f779b6600208","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": {{masterProductId}},\n  \"expectedName\": \"{{masterProductName}}\",\n  \"salePrice\": 160,\n  \"mrp\": 210,\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-modify"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"},{"value":"synthetic-queue-001","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.products.modify\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"},{"id":"d9a11ea3-b5c5-44f7-b92d-b79bbea6a267","name":"409 - BUSY_WRITE_TARGET_CHANGED (synthetic; before save)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/product-modify"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"BUSY_WRITE_TARGET_CHANGED\",\"message\":\"The BUSY destination or its permissions changed before helper execution; nothing was saved.\"}}}"},{"id":"cc441e7d-4842-4812-9507-a3067d2348a5","name":"409 - MASTER_REFERENCE_CHANGED (synthetic; before save)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/product-modify"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"MASTER_REFERENCE_CHANGED\",\"message\":\"An ordinary master reference changed before the save; nothing was saved. Read the references again.\"}}}"}],"_postman_id":"ec288298-96c0-0cb7-c777-577743dacb88"},{"name":"⚠ BUSY group – create account group (writes to BUSY)","id":"b2ebb106-6c1a-5f9f-10a9-a833a06bbb96","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Account Group 01\",\n  \"alias\": \"AZAPI-AG-01\",\n  \"parentGroup\": { \"name\": \"Sundry Debtors\" }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-group-create","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/account-group-create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: <code>confirmMutating</code> = <code>yes</code>, reset after one send) · operation <code>busy.account-groups.create</code>\n<strong>Status (2026-10-17):</strong> in released AI Zeny 0.0.14; installed service-account acceptance passed on COMP0002 / FY 2026 (synthetic groups 1420-1426). The cloud has <strong>no route</strong> for group writes (<code>404</code>; not implemented in the cloud code).</p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq).</p>\n<p>Creates one BUSY account group through BUSY's own COM component. <strong>The place is explicit:</strong> exactly one of <code>parentGroup</code> (<code>{\"code\": n}</code> / <code>{\"name\": \"…\"}</code>, an account group) or <code>topLevel: true</code> — never a silent top level. Names and aliases (1-40) are unique among account groups across the whole tree (<code>409 MASTER_NAME_TAKEN</code>). Use only the development-test company and a new, unique name; never retry blindly (<code>504 BUSY_WRITE_UNCERTAIN</code>: read <code>details.reconciliation</code>; <code>502 BUSY_WRITE_UNVERIFIED</code>: BUSY saved, <code>details.masterId</code>). The PC also runs it for the cloud, which has <strong>no route yet</strong>.</p>\n<p><strong>Answer:</strong> <code>data</code> = <code>{ groupId, name, alias, topLevel, parentGroup, path }</code>; <code>metadata.verifiedFields</code> ends with <code>hierarchy</code>. Stores <code>masterAccountGroupId</code> / <code>masterAccountGroupName</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> 5am; guide <code>docs/public/api/account-and-product-groups.md</code>.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","account-group-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"9eaf28cd-518a-d6ea-a2d7-fcb7ef5d66aa","name":"200 – account group created under Sundry Debtors (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Account Group 01\",\n  \"alias\": \"AZAPI-AG-01\",\n  \"parentGroup\": { \"name\": \"Sundry Debtors\" }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-group-create","description":"**Local** · `POST {{baseUrl}}/api/v1/account-group-create` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.account-groups.create`\n**Status (2026-10-17):** in released AI Zeny 0.0.14; installed service-account acceptance passed on COMP0002 / FY 2026 (synthetic groups 1420-1426). The cloud has **no route** for group writes (`404`; not implemented in the cloud code).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\nCreates one BUSY account group through BUSY's own COM component. **The place is explicit:** exactly one of `parentGroup` (`{\"code\": n}` / `{\"name\": \"…\"}`, an account group) or `topLevel: true` — never a silent top level. Names and aliases (1-40) are unique among account groups across the whole tree (`409 MASTER_NAME_TAKEN`). Use only the development-test company and a new, unique name; never retry blindly (`504 BUSY_WRITE_UNCERTAIN`: read `details.reconciliation`; `502 BUSY_WRITE_UNVERIFIED`: BUSY saved, `details.masterId`). The PC also runs it for the cloud, which has **no route yet**.\n\n**Answer:** `data` = `{ groupId, name, alias, topLevel, parentGroup, path }`; `metadata.verifiedFields` ends with `hierarchy`. Stores `masterAccountGroupId` / `masterAccountGroupName`.\n\nContract: `docs/LOCAL-API.md` 5am; guide `docs/public/api/account-and-product-groups.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"groupId\": 7101,\n    \"name\": \"AZAPI Test Account Group 01\",\n    \"alias\": \"AZAPI-AG-01\",\n    \"topLevel\": false,\n    \"parentGroup\": { \"code\": 116, \"name\": \"Sundry Debtors\" },\n    \"path\": [ { \"code\": 102, \"name\": \"Current Assets\" }, { \"code\": 116, \"name\": \"Sundry Debtors\" } ]\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.account-groups.create\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"masterType\": \"accountGroup\",\n    \"outcome\": \"created\",\n    \"verifiedFields\": [ \"name\", \"alias\", \"parentGroup\", \"hierarchy\" ],\n    \"descendantGroups\": 0,\n    \"elapsedMs\": 3650,\n    \"executedAt\": \"2026-09-26T10:00:00+00:00\"\n  }\n}"},{"id":"80c27dbc-a725-ed48-e856-c54c8e5e8323","name":"422 – parent is not an account group (never made top level)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Account Group 01\",\n  \"alias\": \"AZAPI-AG-01\",\n  \"parentGroup\": { \"name\": \"Sundry Debtors\" }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-group-create","description":"**Local** · `POST {{baseUrl}}/api/v1/account-group-create` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.account-groups.create`\n**Status (2026-10-17):** in released AI Zeny 0.0.14; installed service-account acceptance passed on COMP0002 / FY 2026 (synthetic groups 1420-1426). The cloud has **no route** for group writes (`404`; not implemented in the cloud code).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\nCreates one BUSY account group through BUSY's own COM component. **The place is explicit:** exactly one of `parentGroup` (`{\"code\": n}` / `{\"name\": \"…\"}`, an account group) or `topLevel: true` — never a silent top level. Names and aliases (1-40) are unique among account groups across the whole tree (`409 MASTER_NAME_TAKEN`). Use only the development-test company and a new, unique name; never retry blindly (`504 BUSY_WRITE_UNCERTAIN`: read `details.reconciliation`; `502 BUSY_WRITE_UNVERIFIED`: BUSY saved, `details.masterId`). The PC also runs it for the cloud, which has **no route yet**.\n\n**Answer:** `data` = `{ groupId, name, alias, topLevel, parentGroup, path }`; `metadata.verifiedFields` ends with `hierarchy`. Stores `masterAccountGroupId` / `masterAccountGroupName`.\n\nContract: `docs/LOCAL-API.md` 5am; guide `docs/public/api/account-and-product-groups.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"MASTER_REFERENCE_NOT_FOUND\",\n      \"message\": \"No account group with that code or name exists in this company and financial year.\",\n      \"field\": \"parentGroup\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e11\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"3d72502c-a112-8a64-6218-ed9ecc7ff460","name":"400 – neither parentGroup nor topLevel","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Account Group 01\",\n  \"alias\": \"AZAPI-AG-01\",\n  \"parentGroup\": { \"name\": \"Sundry Debtors\" }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-group-create","description":"**Local** · `POST {{baseUrl}}/api/v1/account-group-create` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.account-groups.create`\n**Status (2026-10-17):** in released AI Zeny 0.0.14; installed service-account acceptance passed on COMP0002 / FY 2026 (synthetic groups 1420-1426). The cloud has **no route** for group writes (`404`; not implemented in the cloud code).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\nCreates one BUSY account group through BUSY's own COM component. **The place is explicit:** exactly one of `parentGroup` (`{\"code\": n}` / `{\"name\": \"…\"}`, an account group) or `topLevel: true` — never a silent top level. Names and aliases (1-40) are unique among account groups across the whole tree (`409 MASTER_NAME_TAKEN`). Use only the development-test company and a new, unique name; never retry blindly (`504 BUSY_WRITE_UNCERTAIN`: read `details.reconciliation`; `502 BUSY_WRITE_UNVERIFIED`: BUSY saved, `details.masterId`). The PC also runs it for the cloud, which has **no route yet**.\n\n**Answer:** `data` = `{ groupId, name, alias, topLevel, parentGroup, path }`; `metadata.verifiedFields` ends with `hierarchy`. Stores `masterAccountGroupId` / `masterAccountGroupName`.\n\nContract: `docs/LOCAL-API.md` 5am; guide `docs/public/api/account-and-product-groups.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"Send exactly one of parentGroup ({\\\"code\\\": n} or {\\\"name\\\": \\\"…\\\"}) or topLevel: true; a group is never made top level by default.\",\n      \"field\": \"parentGroup\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e12\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"f1813b83-4f7b-7e3a-1a62-e815f2339594","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Account Group 01\",\n  \"alias\": \"AZAPI-AG-01\",\n  \"parentGroup\": {\n    \"name\": \"Sundry Debtors\"\n  },\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-group-create"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"},{"value":"synthetic-queue-001","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.account-groups.create\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"}],"_postman_id":"b2ebb106-6c1a-5f9f-10a9-a833a06bbb96"},{"name":"⚠ BUSY group – modify account group (writes to BUSY)","id":"d57dadc9-c9c2-ca7b-db84-23bc2df75a51","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"groupId\": {{masterAccountGroupId}},\n  \"expectedName\": \"{{masterAccountGroupName}}\",\n  \"name\": \"AZAPI Test Account Group 01 Renamed\",\n  \"parentGroup\": { \"name\": \"Sundry Creditors\" }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-group-modify","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/account-group-modify</code> · <strong>⚠ Writes to BUSY</strong> (guarded: <code>confirmMutating</code> = <code>yes</code>, reset after one send) · operation <code>busy.account-groups.modify</code>\n<strong>Status (2026-10-17):</strong> in released AI Zeny 0.0.14; installed service-account acceptance passed on COMP0002 / FY 2026 (rename, alias change and removal, a subtree move, moves to and from top level, the populated-move, cycle, standard-group and type refusals). The cloud has <strong>no route</strong> for group writes (<code>404</code>; not implemented in the cloud code).</p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq).</p>\n<p>Renames, re-aliases or moves one account group named by <code>groupId</code> (<code>expectedName</code> guards against a stale name: <code>409 MASTER_NAME_MISMATCH</code>). Send at least one of <code>name</code>, <code>alias</code> or <code>removeAlias: true</code>, <code>parentGroup</code> (<code>{code}</code> / <code>{name}</code>) or <code>moveToTopLevel: true</code>; <strong>without <code>parentGroup</code> or <code>moveToTopLevel</code> the parent stays as it is</strong>. A move takes the groups below along; refused under the group itself or below it (<code>422 GROUP_PARENT_INVALID</code>) and for a group holding accounts (<code>409 MASTER_CHANGE_UNSUPPORTED</code>). BUSY's standard groups (codes 101-129) are never changed (<code>409 GROUP_PREDEFINED</code>). Success only after BUSY's read-back and a second read of BUSY's database (every other group unchanged). Uses <code>masterAccountGroupId</code> / <code>masterAccountGroupName</code> set by the create; never retry blindly.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> 5am; guide <code>docs/public/api/account-and-product-groups.md</code>.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","account-group-modify"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"c039d63f-41e6-89ea-9f30-d48b666e3c8c","name":"200 – renamed and moved with its subtree (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"groupId\": {{masterAccountGroupId}},\n  \"expectedName\": \"{{masterAccountGroupName}}\",\n  \"name\": \"AZAPI Test Account Group 01 Renamed\",\n  \"parentGroup\": { \"name\": \"Sundry Creditors\" }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-group-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/account-group-modify` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.account-groups.modify`\n**Status (2026-10-17):** in released AI Zeny 0.0.14; installed service-account acceptance passed on COMP0002 / FY 2026 (rename, alias change and removal, a subtree move, moves to and from top level, the populated-move, cycle, standard-group and type refusals). The cloud has **no route** for group writes (`404`; not implemented in the cloud code).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\nRenames, re-aliases or moves one account group named by `groupId` (`expectedName` guards against a stale name: `409 MASTER_NAME_MISMATCH`). Send at least one of `name`, `alias` or `removeAlias: true`, `parentGroup` (`{code}` / `{name}`) or `moveToTopLevel: true`; **without `parentGroup` or `moveToTopLevel` the parent stays as it is**. A move takes the groups below along; refused under the group itself or below it (`422 GROUP_PARENT_INVALID`) and for a group holding accounts (`409 MASTER_CHANGE_UNSUPPORTED`). BUSY's standard groups (codes 101-129) are never changed (`409 GROUP_PREDEFINED`). Success only after BUSY's read-back and a second read of BUSY's database (every other group unchanged). Uses `masterAccountGroupId` / `masterAccountGroupName` set by the create; never retry blindly.\n\nContract: `docs/LOCAL-API.md` 5am; guide `docs/public/api/account-and-product-groups.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"groupId\": 7101,\n    \"name\": \"AZAPI Test Account Group 01 Renamed\",\n    \"alias\": \"AZAPI-AG-01\",\n    \"topLevel\": false,\n    \"parentGroup\": { \"code\": 117, \"name\": \"Sundry Creditors\" },\n    \"path\": [ { \"code\": 103, \"name\": \"Current Liabilities\" }, { \"code\": 117, \"name\": \"Sundry Creditors\" } ]\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.account-groups.modify\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e13\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"masterType\": \"accountGroup\",\n    \"outcome\": \"modified\",\n    \"verifiedFields\": [ \"name\", \"parentGroup\", \"hierarchy\" ],\n    \"descendantGroups\": 2,\n    \"elapsedMs\": 3720,\n    \"executedAt\": \"2026-09-26T10:05:00+00:00\"\n  }\n}"},{"id":"bc80f023-46c6-c5b6-0335-12da419fc8bc","name":"422 – move under one of its own descendants","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"groupId\": {{masterAccountGroupId}},\n  \"expectedName\": \"{{masterAccountGroupName}}\",\n  \"name\": \"AZAPI Test Account Group 01 Renamed\",\n  \"parentGroup\": { \"name\": \"Sundry Creditors\" }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-group-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/account-group-modify` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.account-groups.modify`\n**Status (2026-10-17):** in released AI Zeny 0.0.14; installed service-account acceptance passed on COMP0002 / FY 2026 (rename, alias change and removal, a subtree move, moves to and from top level, the populated-move, cycle, standard-group and type refusals). The cloud has **no route** for group writes (`404`; not implemented in the cloud code).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\nRenames, re-aliases or moves one account group named by `groupId` (`expectedName` guards against a stale name: `409 MASTER_NAME_MISMATCH`). Send at least one of `name`, `alias` or `removeAlias: true`, `parentGroup` (`{code}` / `{name}`) or `moveToTopLevel: true`; **without `parentGroup` or `moveToTopLevel` the parent stays as it is**. A move takes the groups below along; refused under the group itself or below it (`422 GROUP_PARENT_INVALID`) and for a group holding accounts (`409 MASTER_CHANGE_UNSUPPORTED`). BUSY's standard groups (codes 101-129) are never changed (`409 GROUP_PREDEFINED`). Success only after BUSY's read-back and a second read of BUSY's database (every other group unchanged). Uses `masterAccountGroupId` / `masterAccountGroupName` set by the create; never retry blindly.\n\nContract: `docs/LOCAL-API.md` 5am; guide `docs/public/api/account-and-product-groups.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"GROUP_PARENT_INVALID\",\n      \"message\": \"That parent lies below the group itself; a group cannot be moved under one of its own descendants. Nothing was changed.\",\n      \"field\": \"parentGroup\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e14\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"110cec12-75a9-1e25-f961-092aa7c6ba7f","name":"409 – one of BUSY's standard groups (never changed)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"groupId\": {{masterAccountGroupId}},\n  \"expectedName\": \"{{masterAccountGroupName}}\",\n  \"name\": \"AZAPI Test Account Group 01 Renamed\",\n  \"parentGroup\": { \"name\": \"Sundry Creditors\" }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-group-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/account-group-modify` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.account-groups.modify`\n**Status (2026-10-17):** in released AI Zeny 0.0.14; installed service-account acceptance passed on COMP0002 / FY 2026 (rename, alias change and removal, a subtree move, moves to and from top level, the populated-move, cycle, standard-group and type refusals). The cloud has **no route** for group writes (`404`; not implemented in the cloud code).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\nRenames, re-aliases or moves one account group named by `groupId` (`expectedName` guards against a stale name: `409 MASTER_NAME_MISMATCH`). Send at least one of `name`, `alias` or `removeAlias: true`, `parentGroup` (`{code}` / `{name}`) or `moveToTopLevel: true`; **without `parentGroup` or `moveToTopLevel` the parent stays as it is**. A move takes the groups below along; refused under the group itself or below it (`422 GROUP_PARENT_INVALID`) and for a group holding accounts (`409 MASTER_CHANGE_UNSUPPORTED`). BUSY's standard groups (codes 101-129) are never changed (`409 GROUP_PREDEFINED`). Success only after BUSY's read-back and a second read of BUSY's database (every other group unchanged). Uses `masterAccountGroupId` / `masterAccountGroupName` set by the create; never retry blindly.\n\nContract: `docs/LOCAL-API.md` 5am; guide `docs/public/api/account-and-product-groups.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"GROUP_PREDEFINED\",\n      \"message\": \"This is one of BUSY's standard groups, which AI Zeny does not change; nothing was saved. Change it in BUSY if you need to.\",\n      \"field\": \"groupId\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e15\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"7ab80f1d-33b9-8289-ae95-8b3dfedd9e37","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"groupId\": {{masterAccountGroupId}},\n  \"expectedName\": \"{{masterAccountGroupName}}\",\n  \"name\": \"AZAPI Test Account Group 01 Renamed\",\n  \"parentGroup\": { \"name\": \"Sundry Creditors\" },\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-group-modify"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"},{"value":"synthetic-queue-001","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.account-groups.modify\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"}],"_postman_id":"d57dadc9-c9c2-ca7b-db84-23bc2df75a51"},{"name":"⚠ BUSY group – create product group (writes to BUSY)","id":"78fa2de8-b787-036c-8ca3-c61ad45143b3","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Product Group 01\",\n  \"parentGroup\": { \"name\": \"General\" }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-group-create","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/product-group-create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: <code>confirmMutating</code> = <code>yes</code>, reset after one send) · operation <code>busy.product-groups.create</code>\n<strong>Status (2026-10-17):</strong> in released AI Zeny 0.0.14; installed service-account acceptance passed on COMP0002 / FY 2026 (synthetic groups 1420-1426). The cloud has <strong>no route</strong> for group writes (<code>404</code>; not implemented in the cloud code).</p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq).</p>\n<p>Creates one BUSY item (product) group, master type 5, through BUSY's own COM component, with the same rules as the account-group create: exactly one of <code>parentGroup</code> (a <strong>product group</strong>: an account group of the same name is never used) or <code>topLevel: true</code>; names and aliases unique among product groups across the whole tree. Use only the development-test company and a new, unique name; never retry blindly. The PC also runs it for the cloud, which has <strong>no route yet</strong>.</p>\n<p><strong>Answer:</strong> <code>data</code> = <code>{ groupId, name, alias, topLevel, parentGroup, path }</code>. Stores <code>masterProductGroupId</code> / <code>masterProductGroupName</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> 5am; guide <code>docs/public/api/account-and-product-groups.md</code>.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","product-group-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"31706491-b6b3-aa50-439c-9781c9427c32","name":"200 – product group created under General (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Product Group 01\",\n  \"parentGroup\": { \"name\": \"General\" }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-group-create","description":"**Local** · `POST {{baseUrl}}/api/v1/product-group-create` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.product-groups.create`\n**Status (2026-10-17):** in released AI Zeny 0.0.14; installed service-account acceptance passed on COMP0002 / FY 2026 (synthetic groups 1420-1426). The cloud has **no route** for group writes (`404`; not implemented in the cloud code).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\nCreates one BUSY item (product) group, master type 5, through BUSY's own COM component, with the same rules as the account-group create: exactly one of `parentGroup` (a **product group**: an account group of the same name is never used) or `topLevel: true`; names and aliases unique among product groups across the whole tree. Use only the development-test company and a new, unique name; never retry blindly. The PC also runs it for the cloud, which has **no route yet**.\n\n**Answer:** `data` = `{ groupId, name, alias, topLevel, parentGroup, path }`. Stores `masterProductGroupId` / `masterProductGroupName`.\n\nContract: `docs/LOCAL-API.md` 5am; guide `docs/public/api/account-and-product-groups.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"groupId\": 7201,\n    \"name\": \"AZAPI Test Product Group 01\",\n    \"alias\": null,\n    \"topLevel\": false,\n    \"parentGroup\": { \"code\": 401, \"name\": \"General\" },\n    \"path\": [ { \"code\": 401, \"name\": \"General\" } ]\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.product-groups.create\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e16\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"masterType\": \"productGroup\",\n    \"outcome\": \"created\",\n    \"verifiedFields\": [ \"name\", \"parentGroup\", \"hierarchy\" ],\n    \"descendantGroups\": 0,\n    \"elapsedMs\": 3590,\n    \"executedAt\": \"2026-09-26T10:10:00+00:00\"\n  }\n}"},{"id":"7f027f50-5b6f-7255-a7b9-d76d29ec93a6","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Product Group 01\",\n  \"parentGroup\": {\n    \"name\": \"General\"\n  },\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-group-create"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"},{"value":"synthetic-queue-001","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.product-groups.create\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"}],"_postman_id":"78fa2de8-b787-036c-8ca3-c61ad45143b3"},{"name":"⚠ BUSY group – modify product group (writes to BUSY)","id":"8b091a9f-0b70-f69d-b139-4659a89648b7","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"groupId\": {{masterProductGroupId}},\n  \"expectedName\": \"{{masterProductGroupName}}\",\n  \"alias\": \"AZAPI-PG-01\",\n  \"moveToTopLevel\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-group-modify","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/product-group-modify</code> · <strong>⚠ Writes to BUSY</strong> (guarded: <code>confirmMutating</code> = <code>yes</code>, reset after one send) · operation <code>busy.product-groups.modify</code>\n<strong>Status (2026-10-17):</strong> in released AI Zeny 0.0.14; installed service-account acceptance passed on COMP0002 / FY 2026 (rename with an alias, a subtree move, a move to top level with the alias removed, the cycle, standard-group and type refusals). The cloud has <strong>no route</strong> for group writes (<code>404</code>; not implemented in the cloud code).</p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq).</p>\n<p>Renames, re-aliases or moves one product group, as the account-group modify: at least one of <code>name</code>, <code>alias</code> / <code>removeAlias: true</code>, <code>parentGroup</code> / <code>moveToTopLevel: true</code>; the parent stays unless a move is sent; a move is refused for a group that holds items (<code>409 MASTER_CHANGE_UNSUPPORTED</code>) or under itself (<code>422 GROUP_PARENT_INVALID</code>); BUSY's standard group General (code 401) is never changed (<code>409 GROUP_PREDEFINED</code>). The example adds an alias and moves the test group to top level. Uses <code>masterProductGroupId</code> / <code>masterProductGroupName</code>; never retry blindly.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> 5am; guide <code>docs/public/api/account-and-product-groups.md</code>.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","product-group-modify"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"52b29b57-056f-04b4-cb1f-d932be5f2751","name":"200 – alias added and moved to top level (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"groupId\": {{masterProductGroupId}},\n  \"expectedName\": \"{{masterProductGroupName}}\",\n  \"alias\": \"AZAPI-PG-01\",\n  \"moveToTopLevel\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-group-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/product-group-modify` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.product-groups.modify`\n**Status (2026-10-17):** in released AI Zeny 0.0.14; installed service-account acceptance passed on COMP0002 / FY 2026 (rename with an alias, a subtree move, a move to top level with the alias removed, the cycle, standard-group and type refusals). The cloud has **no route** for group writes (`404`; not implemented in the cloud code).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\nRenames, re-aliases or moves one product group, as the account-group modify: at least one of `name`, `alias` / `removeAlias: true`, `parentGroup` / `moveToTopLevel: true`; the parent stays unless a move is sent; a move is refused for a group that holds items (`409 MASTER_CHANGE_UNSUPPORTED`) or under itself (`422 GROUP_PARENT_INVALID`); BUSY's standard group General (code 401) is never changed (`409 GROUP_PREDEFINED`). The example adds an alias and moves the test group to top level. Uses `masterProductGroupId` / `masterProductGroupName`; never retry blindly.\n\nContract: `docs/LOCAL-API.md` 5am; guide `docs/public/api/account-and-product-groups.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"groupId\": 7201,\n    \"name\": \"AZAPI Test Product Group 01\",\n    \"alias\": \"AZAPI-PG-01\",\n    \"topLevel\": true,\n    \"parentGroup\": null,\n    \"path\": []\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.product-groups.modify\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e17\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"masterType\": \"productGroup\",\n    \"outcome\": \"modified\",\n    \"verifiedFields\": [ \"alias\", \"moveToTopLevel\", \"hierarchy\" ],\n    \"descendantGroups\": 0,\n    \"elapsedMs\": 3610,\n    \"executedAt\": \"2026-09-26T10:15:00+00:00\"\n  }\n}"},{"id":"b880532f-d255-9f5a-7049-7c18c0e82fbf","name":"409 – move of a group that holds items","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"groupId\": {{masterProductGroupId}},\n  \"expectedName\": \"{{masterProductGroupName}}\",\n  \"alias\": \"AZAPI-PG-01\",\n  \"moveToTopLevel\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-group-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/product-group-modify` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.product-groups.modify`\n**Status (2026-10-17):** in released AI Zeny 0.0.14; installed service-account acceptance passed on COMP0002 / FY 2026 (rename with an alias, a subtree move, a move to top level with the alias removed, the cycle, standard-group and type refusals). The cloud has **no route** for group writes (`404`; not implemented in the cloud code).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\nRenames, re-aliases or moves one product group, as the account-group modify: at least one of `name`, `alias` / `removeAlias: true`, `parentGroup` / `moveToTopLevel: true`; the parent stays unless a move is sent; a move is refused for a group that holds items (`409 MASTER_CHANGE_UNSUPPORTED`) or under itself (`422 GROUP_PARENT_INVALID`); BUSY's standard group General (code 401) is never changed (`409 GROUP_PREDEFINED`). The example adds an alias and moves the test group to top level. Uses `masterProductGroupId` / `masterProductGroupName`; never retry blindly.\n\nContract: `docs/LOCAL-API.md` 5am; guide `docs/public/api/account-and-product-groups.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"MASTER_CHANGE_UNSUPPORTED\",\n      \"message\": \"This group, or a group below it, holds items. Moving it is not offered, because how BUSY carries balances to the new parent was not tested; move it in BUSY's own window.\",\n      \"field\": \"moveToTopLevel\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e18\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"700cafc0-f5b3-b58e-4bf8-354aa752b020","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"groupId\": {{masterProductGroupId}},\n  \"expectedName\": \"{{masterProductGroupName}}\",\n  \"alias\": \"AZAPI-PG-01\",\n  \"moveToTopLevel\": true,\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-group-modify"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"synthetic-queue-001"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.product-groups.modify\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"}],"_postman_id":"8b091a9f-0b70-f69d-b139-4659a89648b7"},{"name":"⚠ BUSY product dropdown value – create (writes to BUSY)","id":"98985644-e1f5-2c15-b9b4-053677e7cbc6","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"slot\": \"OF1\",\n  \"name\": \"AZAPI Synthetic Value 01\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-optional-field-value-create","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/product-optional-field-value-create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: <code>confirmMutating</code> = <code>yes</code>, reset after one send) · operation <code>busy.products.optional-field-values.create</code></p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq). Account dropdown values have their own request (Access companies).</p>\n<p><strong>Status:</strong> installed service-account acceptance passed 2026-10-17 (installed Host as <code>.\\AIZenySvc</code>, COMP0002 / FY 2026: a value created and verified in SQL, its duplicate <code>409</code>, a text slot <code>422</code>, no extra master). No cloud route.</p>\n<p>Adds one new value to a <strong>product (item) dropdown</strong> optional field, through BUSY's own <code>COtherServices1.SaveOptionalFields</code> (never <code>AddMasterFromXML</code>). Use only the development-test company and a new, unique synthetic name; never retry blindly.</p>\n<p><strong>Rules:</strong> <code>slot</code> <code>OF1</code>–<code>OF10</code> must be a dropdown field of products in that financial year (<code>422 OPTIONAL_FIELD_NOT_DEFINED</code> / <code>OPTIONAL_FIELD_UNSUPPORTED</code>); <code>name</code> 1–40 Latin-1 characters, no surrounding spaces; new in the list, compared without case (<code>409 OPTIONAL_FIELD_VALUE_TAKEN</code> with <code>details.masterId</code>). Verified by reading the list again; an uncertain outcome is reconciled by name and never retried.</p>\n<p><strong>Not offered:</strong> field definitions (create them in BUSY's window). The PC also runs it for the cloud, which has <strong>no route yet</strong>.</p>\n<p><strong>Answer:</strong> <code>data</code> = <code>{ valueId, slot, listType, name }</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> 5an; guide <code>docs/public/api/optional-fields.md</code>.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","product-optional-field-value-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"6e70274c-16b8-9cc9-3d98-ec2a2f036ef0","name":"200 – dropdown value created (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"slot\": \"OF1\",\n  \"name\": \"AZAPI Synthetic Value 01\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-optional-field-value-create","description":"**Local** · `POST {{baseUrl}}/api/v1/product-optional-field-value-create` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.products.optional-field-values.create`\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). Account dropdown values have their own request (Access companies).\n\n**Status:** installed service-account acceptance passed 2026-10-17 (installed Host as `.\\AIZenySvc`, COMP0002 / FY 2026: a value created and verified in SQL, its duplicate `409`, a text slot `422`, no extra master). No cloud route.\n\nAdds one new value to a **product (item) dropdown** optional field, through BUSY's own `COtherServices1.SaveOptionalFields` (never `AddMasterFromXML`). Use only the development-test company and a new, unique synthetic name; never retry blindly.\n\n**Rules:** `slot` `OF1`–`OF10` must be a dropdown field of products in that financial year (`422 OPTIONAL_FIELD_NOT_DEFINED` / `OPTIONAL_FIELD_UNSUPPORTED`); `name` 1–40 Latin-1 characters, no surrounding spaces; new in the list, compared without case (`409 OPTIONAL_FIELD_VALUE_TAKEN` with `details.masterId`). Verified by reading the list again; an uncertain outcome is reconciled by name and never retried.\n\n**Not offered:** field definitions (create them in BUSY's window). The PC also runs it for the cloud, which has **no route yet**.\n\n**Answer:** `data` = `{ valueId, slot, listType, name }`.\n\nContract: `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"valueId\": 7321,\n    \"slot\": \"OF1\",\n    \"listType\": 201,\n    \"name\": \"AZAPI Synthetic Value 01\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.products.optional-field-values.create\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e22\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"verifiedFields\": [ \"slot\", \"name\" ],\n    \"elapsedMs\": 4120,\n    \"executedAt\": \"2026-10-17T12:00:00+00:00\"\n  }\n}"},{"id":"ff35590a-de92-8753-beb0-c90c0b3076b1","name":"409 – OPTIONAL_FIELD_VALUE_TAKEN (synthetic; nothing created)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"slot\": \"OF1\",\n  \"name\": \"AZAPI Synthetic Value 01\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-optional-field-value-create","description":"**Local** · `POST {{baseUrl}}/api/v1/product-optional-field-value-create` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.products.optional-field-values.create`\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). Account dropdown values have their own request (Access companies).\n\n**Status:** installed service-account acceptance passed 2026-10-17 (installed Host as `.\\AIZenySvc`, COMP0002 / FY 2026: a value created and verified in SQL, its duplicate `409`, a text slot `422`, no extra master). No cloud route.\n\nAdds one new value to a **product (item) dropdown** optional field, through BUSY's own `COtherServices1.SaveOptionalFields` (never `AddMasterFromXML`). Use only the development-test company and a new, unique synthetic name; never retry blindly.\n\n**Rules:** `slot` `OF1`–`OF10` must be a dropdown field of products in that financial year (`422 OPTIONAL_FIELD_NOT_DEFINED` / `OPTIONAL_FIELD_UNSUPPORTED`); `name` 1–40 Latin-1 characters, no surrounding spaces; new in the list, compared without case (`409 OPTIONAL_FIELD_VALUE_TAKEN` with `details.masterId`). Verified by reading the list again; an uncertain outcome is reconciled by name and never retried.\n\n**Not offered:** field definitions (create them in BUSY's window). The PC also runs it for the cloud, which has **no route yet**.\n\n**Answer:** `data` = `{ valueId, slot, listType, name }`.\n\nContract: `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"OPTIONAL_FIELD_VALUE_TAKEN\",\n      \"message\": \"This dropdown already has a value with this name (compared without case); nothing was created.\",\n      \"field\": \"name\",\n      \"details\": { \"masterId\": 7321 }\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e23\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"d9d085f9-a0d2-8b87-2229-772ed571ab1a","name":"422 – OPTIONAL_FIELD_UNSUPPORTED, slot is not a dropdown (synthetic; nothing created)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"slot\": \"OF1\",\n  \"name\": \"AZAPI Synthetic Value 01\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-optional-field-value-create","description":"**Local** · `POST {{baseUrl}}/api/v1/product-optional-field-value-create` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.products.optional-field-values.create`\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). Account dropdown values have their own request (Access companies).\n\n**Status:** installed service-account acceptance passed 2026-10-17 (installed Host as `.\\AIZenySvc`, COMP0002 / FY 2026: a value created and verified in SQL, its duplicate `409`, a text slot `422`, no extra master). No cloud route.\n\nAdds one new value to a **product (item) dropdown** optional field, through BUSY's own `COtherServices1.SaveOptionalFields` (never `AddMasterFromXML`). Use only the development-test company and a new, unique synthetic name; never retry blindly.\n\n**Rules:** `slot` `OF1`–`OF10` must be a dropdown field of products in that financial year (`422 OPTIONAL_FIELD_NOT_DEFINED` / `OPTIONAL_FIELD_UNSUPPORTED`); `name` 1–40 Latin-1 characters, no surrounding spaces; new in the list, compared without case (`409 OPTIONAL_FIELD_VALUE_TAKEN` with `details.masterId`). Verified by reading the list again; an uncertain outcome is reconciled by name and never retried.\n\n**Not offered:** field definitions (create them in BUSY's window). The PC also runs it for the cloud, which has **no route yet**.\n\n**Answer:** `data` = `{ valueId, slot, listType, name }`.\n\nContract: `docs/LOCAL-API.md` 5an; guide `docs/public/api/optional-fields.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"OPTIONAL_FIELD_UNSUPPORTED\",\n      \"message\": \"This item field is not a dropdown (BUSY type 1 with \\\"maintain master database\\\"); only a dropdown's values are created. Nothing was written.\",\n      \"field\": \"slot\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e24\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"accd36ce-9325-a8dd-1bed-8bbbb0339c4c","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"slot\": \"OF1\",\n  \"name\": \"AZAPI Synthetic Value 01\",\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/product-optional-field-value-create"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"synthetic-queue-001"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.products.optional-field-values.create\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"}],"_postman_id":"98985644-e1f5-2c15-b9b4-053677e7cbc6"},{"name":"⚠ BUSY contact – create (writes to BUSY)","id":"32e751f0-2e08-e93c-d820-a9293f678833","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Synthetic Contact 01\",\n  \"contactGroup\": { \"name\": \"General\" },\n  \"salutation\": { \"name\": \"Ms.\" },\n  \"address\": {\n    \"line1\": \"1 Example Road\",\n    \"country\": { \"name\": \"India\" },\n    \"state\": { \"name\": \"Delhi\" },\n    \"mobile\": \"9000000101\",\n    \"email\": \"contact01@example.invalid\"\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/contact-create","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/contact-create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: <code>confirmMutating</code> = <code>yes</code>, reset after one send) · operation <code>busy.contacts.create</code></p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq).</p>\n<p><strong>Status:</strong> implemented 2026-10-18 (Local API); <strong>installed service-account acceptance passed 2026-10-18</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0002 / FY 2026: minimal, full and Latin-1 contacts created, two linked to one account, every refusal changing nothing; independent SQL and BUSY's own read-back agree). Not released. No cloud route.</p>\n<p>Creates one BUSY <strong>Contact</strong> master (type 36 — not an account's address \"contact\" text) through BUSY's own contact class <code>CContactMast</code>, in an existing <strong>contact group</strong>, optionally <strong>linked to an existing account</strong> (<code>account</code>, <code>{code}</code> or <code>{name}</code>; an account may have several contacts). Use only the development-test company and a new, unique synthetic name; never retry blindly.</p>\n<p><strong>Body:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>name</code> (1–40), optional <code>alias</code> (1–40), <code>printName</code> (1–60), <strong><code>contactGroup</code></strong> (required), optional <code>salutation</code>, <code>account</code>, <strong><code>address</code></strong> with its required <strong><code>country</code></strong> and optional <code>line1</code>–<code>line4</code> (1–40), <code>state</code>, <code>pinCode</code> (six digits), <code>station</code> (1–30), <code>telephone</code>, <code>mobile</code>, <code>whatsApp</code>, <code>fax</code> (1–30), <code>email</code>. Unknown members (birthday, anniversary, trade type, designation, BUSY's own elements) are <code>400</code>.</p>\n<p><strong>Rules:</strong> every reference (contact group, account, country, state, salutation) must already exist and is resolved <strong>by its own master type</strong> before BUSY is called — BUSY would create a missing one silently, so an unknown or wrong-type reference is <code>422 MASTER_REFERENCE_NOT_FOUND</code>, a shared name <code>422 MASTER_REFERENCE_AMBIGUOUS</code>, and a reference changed just before the save <code>409 CONTACT_REFERENCE_CHANGED</code>. Names and aliases unique among contacts (<code>409 MASTER_NAME_TAKEN</code>). Printable ASCII / Latin-1 text only (BUSY stores other characters as <code>?</code>). <code>whatsApp</code> is stored exactly as sent; without it none is stored (BUSY's window displays 91+mobile; AI Zeny never stores that). Never an upsert; never creates a contact group or account.</p>\n<p><strong>Verification:</strong> BUSY's read-back and a second independent read of BUSY's database (link flag, stored WhatsApp, every reference, no other master created) before a success; <code>502 BUSY_WRITE_UNVERIFIED</code> (saved — do not resend) or <code>504 BUSY_WRITE_UNCERTAIN</code> (reconciled by name: <code>found</code> / <code>notFound</code>; never retried).</p>\n<p><strong>Answer:</strong> <code>data</code> = <code>{ contactId, name, alias, printName, contactGroup, salutation, linked, account, address {…} }</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> 5ap; guide <code>docs/public/api/contacts.md</code>; feature <code>docs/features/BUSY-Contact-Write-API.md</code>.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","contact-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"f25589e1-9d5b-3545-4ea6-18fc10058587","name":"200 – contact created (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Synthetic Contact 01\",\n  \"contactGroup\": { \"name\": \"General\" },\n  \"salutation\": { \"name\": \"Ms.\" },\n  \"address\": {\n    \"line1\": \"1 Example Road\",\n    \"country\": { \"name\": \"India\" },\n    \"state\": { \"name\": \"Delhi\" },\n    \"mobile\": \"9000000101\",\n    \"email\": \"contact01@example.invalid\"\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/contact-create","description":"**Local** · `POST {{baseUrl}}/api/v1/contact-create` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.contacts.create`\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n**Status:** implemented 2026-10-18 (Local API); **installed service-account acceptance passed 2026-10-18** (installed Host as `.\\AIZenySvc`, COMP0002 / FY 2026: minimal, full and Latin-1 contacts created, two linked to one account, every refusal changing nothing; independent SQL and BUSY's own read-back agree). Not released. No cloud route.\n\nCreates one BUSY **Contact** master (type 36 — not an account's address \"contact\" text) through BUSY's own contact class `CContactMast`, in an existing **contact group**, optionally **linked to an existing account** (`account`, `{code}` or `{name}`; an account may have several contacts). Use only the development-test company and a new, unique synthetic name; never retry blindly.\n\n**Body:** `companyCode`, `financialYear`, `name` (1–40), optional `alias` (1–40), `printName` (1–60), **`contactGroup`** (required), optional `salutation`, `account`, **`address`** with its required **`country`** and optional `line1`–`line4` (1–40), `state`, `pinCode` (six digits), `station` (1–30), `telephone`, `mobile`, `whatsApp`, `fax` (1–30), `email`. Unknown members (birthday, anniversary, trade type, designation, BUSY's own elements) are `400`.\n\n**Rules:** every reference (contact group, account, country, state, salutation) must already exist and is resolved **by its own master type** before BUSY is called — BUSY would create a missing one silently, so an unknown or wrong-type reference is `422 MASTER_REFERENCE_NOT_FOUND`, a shared name `422 MASTER_REFERENCE_AMBIGUOUS`, and a reference changed just before the save `409 CONTACT_REFERENCE_CHANGED`. Names and aliases unique among contacts (`409 MASTER_NAME_TAKEN`). Printable ASCII / Latin-1 text only (BUSY stores other characters as `?`). `whatsApp` is stored exactly as sent; without it none is stored (BUSY's window displays 91+mobile; AI Zeny never stores that). Never an upsert; never creates a contact group or account.\n\n**Verification:** BUSY's read-back and a second independent read of BUSY's database (link flag, stored WhatsApp, every reference, no other master created) before a success; `502 BUSY_WRITE_UNVERIFIED` (saved — do not resend) or `504 BUSY_WRITE_UNCERTAIN` (reconciled by name: `found` / `notFound`; never retried).\n\n**Answer:** `data` = `{ contactId, name, alias, printName, contactGroup, salutation, linked, account, address {…} }`.\n\nContract: `docs/LOCAL-API.md` 5ap; guide `docs/public/api/contacts.md`; feature `docs/features/BUSY-Contact-Write-API.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"contactId\": 7401,\n    \"name\": \"AZAPI Synthetic Contact 01\",\n    \"alias\": null,\n    \"printName\": null,\n    \"contactGroup\": { \"code\": 405, \"name\": \"General\" },\n    \"salutation\": { \"code\": 1284, \"name\": \"Ms.\" },\n    \"linked\": false,\n    \"account\": null,\n    \"address\": {\n      \"line1\": \"1 Example Road\", \"line2\": null, \"line3\": null, \"line4\": null,\n      \"country\": { \"code\": 1000, \"name\": \"India\" },\n      \"state\": { \"code\": 1053, \"name\": \"Delhi\" },\n      \"pinCode\": null, \"station\": null, \"telephone\": null,\n      \"mobile\": \"9000000101\", \"whatsApp\": null, \"fax\": null,\n      \"email\": \"contact01@example.invalid\"\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.contacts.create\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"masterType\": \"contact\",\n    \"outcome\": \"created\",\n    \"verifiedFields\": [\"name\", \"contactGroup\", \"salutation\", \"address.line1\", \"address.country\", \"address.state\", \"address.mobile\", \"address.email\"],\n    \"elapsedMs\": 3650,\n    \"executedAt\": \"2026-10-17T10:00:00+00:00\"\n  }\n}"},{"id":"248ae2bf-94ae-961f-8c23-3e0eaf35b1c0","name":"422 – account does not exist (nothing created; synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Synthetic Contact 01\",\n  \"contactGroup\": { \"name\": \"General\" },\n  \"salutation\": { \"name\": \"Ms.\" },\n  \"address\": {\n    \"line1\": \"1 Example Road\",\n    \"country\": { \"name\": \"India\" },\n    \"state\": { \"name\": \"Delhi\" },\n    \"mobile\": \"9000000101\",\n    \"email\": \"contact01@example.invalid\"\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/contact-create","description":"**Local** · `POST {{baseUrl}}/api/v1/contact-create` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.contacts.create`\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n**Status:** implemented 2026-10-18 (Local API); **installed service-account acceptance passed 2026-10-18** (installed Host as `.\\AIZenySvc`, COMP0002 / FY 2026: minimal, full and Latin-1 contacts created, two linked to one account, every refusal changing nothing; independent SQL and BUSY's own read-back agree). Not released. No cloud route.\n\nCreates one BUSY **Contact** master (type 36 — not an account's address \"contact\" text) through BUSY's own contact class `CContactMast`, in an existing **contact group**, optionally **linked to an existing account** (`account`, `{code}` or `{name}`; an account may have several contacts). Use only the development-test company and a new, unique synthetic name; never retry blindly.\n\n**Body:** `companyCode`, `financialYear`, `name` (1–40), optional `alias` (1–40), `printName` (1–60), **`contactGroup`** (required), optional `salutation`, `account`, **`address`** with its required **`country`** and optional `line1`–`line4` (1–40), `state`, `pinCode` (six digits), `station` (1–30), `telephone`, `mobile`, `whatsApp`, `fax` (1–30), `email`. Unknown members (birthday, anniversary, trade type, designation, BUSY's own elements) are `400`.\n\n**Rules:** every reference (contact group, account, country, state, salutation) must already exist and is resolved **by its own master type** before BUSY is called — BUSY would create a missing one silently, so an unknown or wrong-type reference is `422 MASTER_REFERENCE_NOT_FOUND`, a shared name `422 MASTER_REFERENCE_AMBIGUOUS`, and a reference changed just before the save `409 CONTACT_REFERENCE_CHANGED`. Names and aliases unique among contacts (`409 MASTER_NAME_TAKEN`). Printable ASCII / Latin-1 text only (BUSY stores other characters as `?`). `whatsApp` is stored exactly as sent; without it none is stored (BUSY's window displays 91+mobile; AI Zeny never stores that). Never an upsert; never creates a contact group or account.\n\n**Verification:** BUSY's read-back and a second independent read of BUSY's database (link flag, stored WhatsApp, every reference, no other master created) before a success; `502 BUSY_WRITE_UNVERIFIED` (saved — do not resend) or `504 BUSY_WRITE_UNCERTAIN` (reconciled by name: `found` / `notFound`; never retried).\n\n**Answer:** `data` = `{ contactId, name, alias, printName, contactGroup, salutation, linked, account, address {…} }`.\n\nContract: `docs/LOCAL-API.md` 5ap; guide `docs/public/api/contacts.md`; feature `docs/features/BUSY-Contact-Write-API.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.contacts.create\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e11\",\n    \"error\": {\n      \"code\": \"MASTER_REFERENCE_NOT_FOUND\",\n      \"message\": \"No account with that code or name exists in this company and financial year.\",\n      \"field\": \"account\"\n    }\n  }\n}"},{"id":"92c66f03-243c-ae92-05ff-b9de0c4a9ae6","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Synthetic Contact 01\",\n  \"contactGroup\": {\n    \"name\": \"General\"\n  },\n  \"salutation\": {\n    \"name\": \"Ms.\"\n  },\n  \"address\": {\n    \"line1\": \"1 Example Road\",\n    \"country\": {\n      \"name\": \"India\"\n    },\n    \"state\": {\n      \"name\": \"Delhi\"\n    },\n    \"mobile\": \"9000000101\",\n    \"email\": \"contact01@example.invalid\"\n  },\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/contact-create"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"},{"value":"synthetic-queue-001","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.contacts.create\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"}],"_postman_id":"32e751f0-2e08-e93c-d820-a9293f678833"},{"name":"⚠ BUSY contact – modify, link or unlink (writes to BUSY)","id":"6338e118-042c-1c8d-ac9b-f521ddd9eec3","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"contactId\": {{lastContactId}},\n  \"expectedName\": \"AZAPI Synthetic Contact 01\",\n  \"address\": { \"mobile\": \"9000000102\", \"whatsApp\": \"9000000102\" },\n  \"clear\": [ \"address.line2\" ]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/contact-modify","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/contact-modify</code> · <strong>⚠ Writes to BUSY</strong> (guarded: <code>confirmMutating</code> = <code>yes</code>, reset after one send) · operation <code>busy.contacts.modify</code></p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq).</p>\n<p><strong>Status:</strong> implemented 2026-10-18 (Local API); <strong>installed service-account acceptance passed 2026-10-18</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0002 / FY 2026: rename, mobile with WhatsApp kept or empty, state change and clears, salutation, relink, unlink, link and alias; refusals changing nothing; independent SQL and BUSY's own read-back agree). Not released. No cloud route.</p>\n<p>Changes one existing BUSY contact (named by <code>contactId</code>, BUSY's code; it never changes): BUSY's own contact is loaded through <code>CContactMast</code>, only the requested elements change, and every reference and the WhatsApp number are stated again explicitly. What you do not send keeps its stored value. Use only synthetic contacts you created on the development-test company; never retry blindly.</p>\n<p><strong>Body:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>contactId</code>, optional <code>expectedName</code> (<code>409 MASTER_NAME_MISMATCH</code> when it differs), and at least one of <code>name</code>, <code>alias</code> / <code>removeAlias: true</code>, <code>printName</code>, <code>contactGroup</code>, <code>salutation</code>, <code>account</code> (link or relink to an existing account) / <code>unlinkAccount: true</code>, <code>address</code> members, <code>clear</code> (<code>printName</code>, <code>address.line1</code>–<code>line4</code>, <code>address.pinCode</code>, <code>address.station</code>, <code>address.telephone</code>, <code>address.mobile</code>, <code>address.whatsApp</code>, <code>address.fax</code>, <code>address.email</code>). A field may not be both set and cleared; the country and state can be changed, never cleared.</p>\n<p><strong>Link:</strong> <code>linked</code> is BUSY's link flag; <code>account</code> is <code>null</code> whenever it is not set (BUSY may keep a stale code after an unlink; it is never shown or repaired). Unlinking a contact that is not linked is <code>409 MASTER_CHANGE_UNSUPPORTED</code>.</p>\n<p><strong>WhatsApp:</strong> changing the mobile number never stores BUSY's displayed 91+mobile; a stored WhatsApp number is kept unless you send or clear it.</p>\n<p><strong>Country:</strong> a contact whose stored country is not a country master needs <code>address.country</code> with the change (<code>422 CONTACT_COUNTRY_REQUIRED</code>).</p>\n<p><strong>Verification and outcomes:</strong> as the create; an uncertain modify is <code>504 BUSY_WRITE_UNCERTAIN</code> with <code>reconciliation: notChecked</code> — read the contact in BUSY, never resend.</p>\n<p>The body uses <code>{{lastContactId}}</code>, set by the create request's tests.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> 5ap; guide <code>docs/public/api/contacts.md</code>.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","contact-modify"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"5b977fca-cf84-09b3-ee97-2a644e2021d2","name":"200 – contact unlinked, WhatsApp set (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"contactId\": {{lastContactId}},\n  \"expectedName\": \"AZAPI Synthetic Contact 01\",\n  \"address\": { \"mobile\": \"9000000102\", \"whatsApp\": \"9000000102\" },\n  \"clear\": [ \"address.line2\" ]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/contact-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/contact-modify` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.contacts.modify`\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n**Status:** implemented 2026-10-18 (Local API); **installed service-account acceptance passed 2026-10-18** (installed Host as `.\\AIZenySvc`, COMP0002 / FY 2026: rename, mobile with WhatsApp kept or empty, state change and clears, salutation, relink, unlink, link and alias; refusals changing nothing; independent SQL and BUSY's own read-back agree). Not released. No cloud route.\n\nChanges one existing BUSY contact (named by `contactId`, BUSY's code; it never changes): BUSY's own contact is loaded through `CContactMast`, only the requested elements change, and every reference and the WhatsApp number are stated again explicitly. What you do not send keeps its stored value. Use only synthetic contacts you created on the development-test company; never retry blindly.\n\n**Body:** `companyCode`, `financialYear`, `contactId`, optional `expectedName` (`409 MASTER_NAME_MISMATCH` when it differs), and at least one of `name`, `alias` / `removeAlias: true`, `printName`, `contactGroup`, `salutation`, `account` (link or relink to an existing account) / `unlinkAccount: true`, `address` members, `clear` (`printName`, `address.line1`–`line4`, `address.pinCode`, `address.station`, `address.telephone`, `address.mobile`, `address.whatsApp`, `address.fax`, `address.email`). A field may not be both set and cleared; the country and state can be changed, never cleared.\n\n**Link:** `linked` is BUSY's link flag; `account` is `null` whenever it is not set (BUSY may keep a stale code after an unlink; it is never shown or repaired). Unlinking a contact that is not linked is `409 MASTER_CHANGE_UNSUPPORTED`.\n\n**WhatsApp:** changing the mobile number never stores BUSY's displayed 91+mobile; a stored WhatsApp number is kept unless you send or clear it.\n\n**Country:** a contact whose stored country is not a country master needs `address.country` with the change (`422 CONTACT_COUNTRY_REQUIRED`).\n\n**Verification and outcomes:** as the create; an uncertain modify is `504 BUSY_WRITE_UNCERTAIN` with `reconciliation: notChecked` — read the contact in BUSY, never resend.\n\nThe body uses `{{lastContactId}}`, set by the create request's tests.\n\nContract: `docs/LOCAL-API.md` 5ap; guide `docs/public/api/contacts.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"contactId\": 7401,\n    \"name\": \"AZAPI Synthetic Contact 01\",\n    \"alias\": null,\n    \"printName\": null,\n    \"contactGroup\": { \"code\": 405, \"name\": \"General\" },\n    \"salutation\": { \"code\": 1284, \"name\": \"Ms.\" },\n    \"linked\": false,\n    \"account\": null,\n    \"address\": {\n      \"line1\": \"1 Example Road\", \"line2\": null, \"line3\": null, \"line4\": null,\n      \"country\": { \"code\": 1000, \"name\": \"India\" },\n      \"state\": { \"code\": 1053, \"name\": \"Delhi\" },\n      \"pinCode\": null, \"station\": null, \"telephone\": null,\n      \"mobile\": \"9000000102\", \"whatsApp\": \"9000000102\", \"fax\": null,\n      \"email\": \"contact01@example.invalid\"\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.contacts.modify\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e12\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"masterType\": \"contact\",\n    \"outcome\": \"modified\",\n    \"verifiedFields\": [\"unlinkAccount\", \"address.mobile\", \"address.whatsApp\", \"address.line2\"],\n    \"elapsedMs\": 3650,\n    \"executedAt\": \"2026-10-17T10:00:00+00:00\"\n  }\n}"},{"id":"2243bd83-8777-a47f-7c99-1905dac379f2","name":"504 – outcome unknown, do not resend (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"contactId\": {{lastContactId}},\n  \"expectedName\": \"AZAPI Synthetic Contact 01\",\n  \"address\": { \"mobile\": \"9000000102\", \"whatsApp\": \"9000000102\" },\n  \"clear\": [ \"address.line2\" ]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/contact-modify","description":"**Local** · `POST {{baseUrl}}/api/v1/contact-modify` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.contacts.modify`\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n**Status:** implemented 2026-10-18 (Local API); **installed service-account acceptance passed 2026-10-18** (installed Host as `.\\AIZenySvc`, COMP0002 / FY 2026: rename, mobile with WhatsApp kept or empty, state change and clears, salutation, relink, unlink, link and alias; refusals changing nothing; independent SQL and BUSY's own read-back agree). Not released. No cloud route.\n\nChanges one existing BUSY contact (named by `contactId`, BUSY's code; it never changes): BUSY's own contact is loaded through `CContactMast`, only the requested elements change, and every reference and the WhatsApp number are stated again explicitly. What you do not send keeps its stored value. Use only synthetic contacts you created on the development-test company; never retry blindly.\n\n**Body:** `companyCode`, `financialYear`, `contactId`, optional `expectedName` (`409 MASTER_NAME_MISMATCH` when it differs), and at least one of `name`, `alias` / `removeAlias: true`, `printName`, `contactGroup`, `salutation`, `account` (link or relink to an existing account) / `unlinkAccount: true`, `address` members, `clear` (`printName`, `address.line1`–`line4`, `address.pinCode`, `address.station`, `address.telephone`, `address.mobile`, `address.whatsApp`, `address.fax`, `address.email`). A field may not be both set and cleared; the country and state can be changed, never cleared.\n\n**Link:** `linked` is BUSY's link flag; `account` is `null` whenever it is not set (BUSY may keep a stale code after an unlink; it is never shown or repaired). Unlinking a contact that is not linked is `409 MASTER_CHANGE_UNSUPPORTED`.\n\n**WhatsApp:** changing the mobile number never stores BUSY's displayed 91+mobile; a stored WhatsApp number is kept unless you send or clear it.\n\n**Country:** a contact whose stored country is not a country master needs `address.country` with the change (`422 CONTACT_COUNTRY_REQUIRED`).\n\n**Verification and outcomes:** as the create; an uncertain modify is `504 BUSY_WRITE_UNCERTAIN` with `reconciliation: notChecked` — read the contact in BUSY, never resend.\n\nThe body uses `{{lastContactId}}`, set by the create request's tests.\n\nContract: `docs/LOCAL-API.md` 5ap; guide `docs/public/api/contacts.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.contacts.modify\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e13\",\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"BUSY stopped while saving the master, so whether it was saved is not known. Check the master in BUSY (or read it through the Local API) before trying again.\",\n      \"details\": { \"masterId\": 7401, \"reconciliation\": \"notChecked\" }\n    }\n  }\n}"},{"id":"65556fe0-b04e-d59e-1f1c-65eab42e01eb","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"contactId\": {{lastContactId}},\n  \"expectedName\": \"AZAPI Synthetic Contact 01\",\n  \"address\": { \"mobile\": \"9000000102\", \"whatsApp\": \"9000000102\" },\n  \"clear\": [ \"address.line2\" ],\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/contact-modify"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"},{"value":"synthetic-queue-001","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.contacts.modify\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"}],"_postman_id":"6338e118-042c-1c8d-ac9b-f521ddd9eec3"},{"name":"⚠ BUSY account dropdown value – create (writes to BUSY; Access companies)","id":"f3db18be-d3d5-81d8-3b01-5e19b1b6e8a2","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"slot\": \"OF5\",\n  \"name\": \"AZAPI Synthetic Tier 01\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-optional-field-value-create","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/account-optional-field-value-create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: <code>confirmMutating</code> = <code>yes</code>, reset after one send) · operation <code>busy.accounts.optional-field-values.create</code></p>\n<p><strong>Status (2026-10-18):</strong> implemented with the Access write support; the live test through the product path on a sandbox copy of the COMP0001 / FY 2026 Access test company <strong>passed</strong> as the signed-in user (a value created in list 255 and verified; its duplicate <code>409 OPTIONAL_FIELD_VALUE_TAKEN</code>). <strong>Installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: a value created in list 255 and verified, its duplicate <code>409</code>; on the SQL Server company COMP0002 the route answers <code>422 OPTIONAL_FIELD_UNSUPPORTED</code>). No cloud route.</p>\n<p>Adds one new value to an <strong>account (ledger) dropdown</strong> optional field, through BUSY's own <code>COtherServices1.SaveOptionalFields</code> (list type 250 + slot; never <code>AddMasterFromXML</code>). <strong>Access companies only</strong>: on a SQL Server company account dropdowns are not yet proven and the request is refused (<code>422 OPTIONAL_FIELD_UNSUPPORTED</code>). Use only a test company and a new, unique synthetic name; never retry blindly.</p>\n<p><strong>Rules:</strong> <code>slot</code> <code>OF1</code>–<code>OF10</code> must be a dropdown field of accounts in that financial year (<code>422 OPTIONAL_FIELD_NOT_DEFINED</code> / <code>OPTIONAL_FIELD_UNSUPPORTED</code>); <code>name</code> 1–40 Latin-1 characters, no surrounding spaces; new in the list, compared without case (<code>409 OPTIONAL_FIELD_VALUE_TAKEN</code> with <code>details.masterId</code>). Verified by reading the list again; an uncertain outcome is reconciled by name and never retried.</p>\n<p><strong>Answer:</strong> <code>data</code> = <code>{ valueId, slot, listType, name }</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> 5an and 5aq; guide <code>docs/public/api/optional-fields.md</code>; feature <code>docs/features/BUSY-Write-Provider-Support.md</code>.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","account-optional-field-value-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"9b4bfb7a-cd0e-6c1c-b7a0-dd1bedcfe89c","name":"200 – account dropdown value created, Access company (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"slot\": \"OF5\",\n  \"name\": \"AZAPI Synthetic Tier 01\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-optional-field-value-create","description":"**Local** · `POST {{baseUrl}}/api/v1/account-optional-field-value-create` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.accounts.optional-field-values.create`\n\n**Status (2026-10-18):** implemented with the Access write support; the live test through the product path on a sandbox copy of the COMP0001 / FY 2026 Access test company **passed** as the signed-in user (a value created in list 255 and verified; its duplicate `409 OPTIONAL_FIELD_VALUE_TAKEN`). **Installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: a value created in list 255 and verified, its duplicate `409`; on the SQL Server company COMP0002 the route answers `422 OPTIONAL_FIELD_UNSUPPORTED`). No cloud route.\n\nAdds one new value to an **account (ledger) dropdown** optional field, through BUSY's own `COtherServices1.SaveOptionalFields` (list type 250 + slot; never `AddMasterFromXML`). **Access companies only**: on a SQL Server company account dropdowns are not yet proven and the request is refused (`422 OPTIONAL_FIELD_UNSUPPORTED`). Use only a test company and a new, unique synthetic name; never retry blindly.\n\n**Rules:** `slot` `OF1`–`OF10` must be a dropdown field of accounts in that financial year (`422 OPTIONAL_FIELD_NOT_DEFINED` / `OPTIONAL_FIELD_UNSUPPORTED`); `name` 1–40 Latin-1 characters, no surrounding spaces; new in the list, compared without case (`409 OPTIONAL_FIELD_VALUE_TAKEN` with `details.masterId`). Verified by reading the list again; an uncertain outcome is reconciled by name and never retried.\n\n**Answer:** `data` = `{ valueId, slot, listType, name }`.\n\nContract: `docs/LOCAL-API.md` 5an and 5aq; guide `docs/public/api/optional-fields.md`; feature `docs/features/BUSY-Write-Provider-Support.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"valueId\": 7302, \"slot\": \"OF5\", \"listType\": 255, \"name\": \"AZAPI Synthetic Tier 01\" },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.accounts.optional-field-values.create\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"verifiedFields\": [\"slot\", \"name\"],\n    \"elapsedMs\": 2850,\n    \"executedAt\": \"2026-10-18T10:00:00+00:00\"\n  }\n}"},{"id":"a649b79c-79af-9ed7-6e8d-e9d43069e3d4","name":"422 – OPTIONAL_FIELD_UNSUPPORTED, a SQL Server company (synthetic; nothing created)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"slot\": \"OF5\",\n  \"name\": \"AZAPI Synthetic Tier 01\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-optional-field-value-create","description":"**Local** · `POST {{baseUrl}}/api/v1/account-optional-field-value-create` · **⚠ Writes to BUSY** (guarded: `confirmMutating` = `yes`, reset after one send) · operation `busy.accounts.optional-field-values.create`\n\n**Status (2026-10-18):** implemented with the Access write support; the live test through the product path on a sandbox copy of the COMP0001 / FY 2026 Access test company **passed** as the signed-in user (a value created in list 255 and verified; its duplicate `409 OPTIONAL_FIELD_VALUE_TAKEN`). **Installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: a value created in list 255 and verified, its duplicate `409`; on the SQL Server company COMP0002 the route answers `422 OPTIONAL_FIELD_UNSUPPORTED`). No cloud route.\n\nAdds one new value to an **account (ledger) dropdown** optional field, through BUSY's own `COtherServices1.SaveOptionalFields` (list type 250 + slot; never `AddMasterFromXML`). **Access companies only**: on a SQL Server company account dropdowns are not yet proven and the request is refused (`422 OPTIONAL_FIELD_UNSUPPORTED`). Use only a test company and a new, unique synthetic name; never retry blindly.\n\n**Rules:** `slot` `OF1`–`OF10` must be a dropdown field of accounts in that financial year (`422 OPTIONAL_FIELD_NOT_DEFINED` / `OPTIONAL_FIELD_UNSUPPORTED`); `name` 1–40 Latin-1 characters, no surrounding spaces; new in the list, compared without case (`409 OPTIONAL_FIELD_VALUE_TAKEN` with `details.masterId`). Verified by reading the list again; an uncertain outcome is reconciled by name and never retried.\n\n**Answer:** `data` = `{ valueId, slot, listType, name }`.\n\nContract: `docs/LOCAL-API.md` 5an and 5aq; guide `docs/public/api/optional-fields.md`; feature `docs/features/BUSY-Write-Provider-Support.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.accounts.optional-field-values.create\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e11\",\n    \"error\": {\n      \"code\": \"OPTIONAL_FIELD_UNSUPPORTED\",\n      \"message\": \"On SQL Server companies account dropdown fields are not supported yet: BUSY's account value lists are proven on Access companies but not yet on SQL Server. Set the value in BUSY. Nothing was written.\",\n      \"field\": \"slot\"\n    }\n  }\n}"},{"id":"cc10dd55-89b7-837f-3aaa-44755a146cad","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"slot\": \"OF5\",\n  \"name\": \"AZAPI Synthetic Tier 01\",\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-optional-field-value-create"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"synthetic-queue-001"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.accounts.optional-field-values.create\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"}],"_postman_id":"f3db18be-d3d5-81d8-3b01-5e19b1b6e8a2"}],"id":"46f2f5a3-92b1-448e-a292-ce391bdcf02a","description":"<p><strong>Writes to the BUSY books.</strong> Create and change account and product masters through BUSY's own COM component (SQL Server companies with a SQL login). Each request is skipped unless <code>confirmMutating</code> = <code>yes</code>, and resets it after one send. Use only the development-test company (<code>targetCompanyCode</code> = COMP0002). Never retry blindly after <code>BUSY_WRITE_UNCERTAIN</code> / <code>BUSY_WRITE_UNVERIFIED</code>. The same four routes exist in the cloud (Cloud → ⚠ Master Create &amp; Modify), but the <strong>current Windows build refuses relayed writes</strong>: write through these Local requests today.</p>\n","_postman_id":"46f2f5a3-92b1-448e-a292-ce391bdcf02a","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ Voucher Create — WRITES TO BUSY","item":[{"name":"⚠ BUSY sales order – create (writes to BUSY)","id":"9c52eabc-ed2c-4599-ff04-f787702bb271","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-POSTMAN ACC 01\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Synthetic colour: blue\", \"\", \"Synthetic size: large\"] },\n    { \"item\": { \"code\": 1348 }, \"quantity\": 1, \"rate\": 200 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/sales-order-create</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>⚠ Writes to BUSY</strong> (Development Local Send requires no separate confirmation)\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>orderReference</code>, <code>date</code>, <code>customer</code>, <code>saleType</code>, <code>materialCenter</code>, <code>lines</code>, <code>lines[].item</code>, <code>lines[].quantity</code>, <code>lines[].rate</code> · operation <code>busy.sales-orders.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq). The series must number automatically (<code>422 SALES_ORDER_SERIES_UNSUPPORTED</code>).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books. Run manually, one at a time.</strong> <code>busy.sales-orders.create</code> (<code>POST /api/v1/sales-order-create</code>) creates one BUSY sales order through BUSY's own COM component on this PC. <strong>Create only</strong>: it never changes, cancels or deletes an order. <strong>SQL Server companies with a SQL login, or Access companies</strong>. Never run from scripts. Through the cloud: Windows relays it from source commit <code>6e3f9aa</code> onward with the master writes' rules, but the AI Zeny cloud has no <code>/v1/sales-order-create</code> route yet (2026-10-13), so use this Local request; see <code>docs/integration/Cloud-Sales-Order-Relay-Handoff.md</code>.</p>\n<p><strong>How it works.</strong> BUSY numbers the order from the series. Your <code>orderReference</code> (1-60 characters) is stored in the order's narration and must be unique among the company's sales orders of the year. AI Zeny calculates each line's amount and GST from the item's tax category in BUSY (CGST + SGST for a local sale type, IGST for a central one); the sale type must take GST per item and match the selected pricing mode (for example <code>Local-ItemWise</code>, <code>Central-ItemWise</code>). BUSY's read-back and the saved rows are compared with what was sent before a success is answered.</p>\n<p><strong>2-decimal net rate.</strong> BUSY keeps a sales order's price to <strong>2 decimals</strong>, so each line's rate less its discount (<code>rate × (1 − discountPercent / 100)</code>) must come to at most 2 decimals. Otherwise the line is refused with <code>400 INVALID_PARAMETER</code> (field <code>lines[i].discountPercent</code>) before anything reaches BUSY — it is never rounded. Example: 150 less 10 % = 135 is accepted; 999.99 less 2 % = 979.9902 is refused (installed acceptance 2026-10-13: BUSY stored it as 979.99).</p>\n<p><strong>Safe test guidance</strong></p>\n<ul>\n<li>Select a development-test <code>companyCode</code> (<code>COMP0002</code> / FY 2026 in this environment; use <code>COMP0001</code> for Access tests). With <code>autoVoucherReferences=yes</code>, each Local Send generates and stores a fresh 25-character synthetic <code>salesOrderReference</code>. Set that switch to <code>no</code> to supply your own unique reference.</li>\n<li>Nothing is deleted automatically: a created test order stays in BUSY.</li>\n<li><strong>Never retry blindly.</strong> Automatic references change on each Send, so another Send can create another voucher; reconcile an uncertain result first. Sending the same <code>salesOrderReference</code> again is refused (<code>409 SALES_ORDER_REFERENCE_TAKEN</code>, <code>details.orderId</code>) if the first send saved, a manually reused reference is blocked. After <code>504 BUSY_WRITE_UNCERTAIN</code>, read <code>metadata.error.details.reconciliation</code> (<code>found</code> + <code>orderId</code>, <code>notFound</code>, <code>notChecked</code>) and check BUSY before anything else.</li>\n<li><code>502 BUSY_WRITE_UNVERIFIED</code> means BUSY <strong>did</strong> save but its read-back differs (<code>details.orderId</code>, <code>details.mismatchedFields</code>): check it in BUSY.</li>\n<li>One BUSY job at a time on the PC (shared with voucher PDFs and master writes), up to 2 minutes: give the request a long timeout.</li>\n</ul>\n<p><strong>Body:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>orderReference</code>, <code>date</code> (<code>YYYY-MM-DD</code> in the year), <code>voucherSeries</code> (optional when only one), <code>customer</code>, <code>saleType</code>, <code>materialCenter</code> (each <code>{\"code\": n}</code> or <code>{\"name\": \"…\"}</code>), <code>lines</code> (1-100: <code>item</code>, <code>quantity</code> &gt; 0 with ≤ 3 decimals, <code>rate</code> ≥ 0 with ≤ 2 decimals, optional <code>discountPercent</code> 0-100 with ≤ 2 decimals; rate less discount ≤ 2 decimals; optional <code>description</code>, see below). In Auto, explicit amounts and totals are refused; Manual follows the GST billing-mode contract. Order numbers and unknown members are refused. Body up to 64 KiB.</p>\n<p><strong>Sets:</strong> <code>salesOrderId</code> on success. Public guide: <code>docs/public/api/sales-order-create.md</code>.</p>\n<p><strong>Line descriptions (owner acceptance 2026-10-19; <code>docs/features/BUSY-Voucher-Line-Descriptions.md</code>):</strong> <code>lines[].description</code> is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; <code>\"\"</code> or <code>null</code> keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise <code>422 BUSY_SETTING_REQUIRED</code> (<code>lines[i].description</code>) or <code>422 DESCRIPTION_LINE_NOT_ALLOWED</code> (<code>lines[i].description[n]</code>), nothing saved. SQL Server companies take Latin-1 characters only (<code>400</code>, before BUSY); Access companies any text. The answer's lines carry <code>description</code> as saved. A Host before 2026-10-19 refuses the member (<code>400 BAD_REQUEST</code>). Public guide: <code>docs/public/api/line-descriptions.md</code>.</p>\n<p><strong>GST billing modes (bounded internal 0.0.15 candidate accepted 2026-10-20 on Access and SQL Server; 0.0.16 release smoke was narrower):</strong> Optional <code>taxCalculation</code> is <code>auto</code> (default) or <code>manual</code>; optional <code>pricingMode</code> is <code>gstExclusive</code> (default) or <code>gstInclusive</code>. JSON <code>null</code> selects each default. One pricing mode applies to every line. <code>rate</code> is the unit price before discount, GST included only for <code>gstInclusive</code>; choose a native item-wise sale/purchase type whose inclusive setting matches. Tax rates come from each selected item's configured category for this company/year; local uses CGST+SGST, central uses IGST. Mixed-rate lines are allowed. Auto computes money using decimal arithmetic. Manual requires every line's <code>amounts</code> and document <code>totals</code>, each with <code>taxableAmount</code>, <code>cgst</code>, <code>sgst</code>, <code>igst</code>, <code>amount</code> (JSON numbers, max two decimals). <code>amount</code> equals taxable plus components; totals equal exact line sums. Local IGST and central CGST/SGST must be zero; submitted values must satisfy the narrow configured-rate and one-paisa bounds in <code>docs/features/BUSY-GST-Billing-Modes-Create-API.md</code>. No balancing charge or silent replacement. Returns submit positive amounts; BUSY posts reversal signs. Malformed JSON or unknown fields: <code>400 BAD_REQUEST</code>; missing or inconsistent Manual amounts: <code>400 INVALID_PARAMETER</code>; invalid configured-rate/treatment: <code>422 GST_AMOUNTS_INVALID</code>; unproven new-mode combination: <code>422 GST_MODE_UNSUPPORTED</code>; changed configuration before save: <code>409 GST_CONFIGURATION_CHANGED</code>. If saved read-back mismatches: <code>502 BUSY_WRITE_UNVERIFIED</code> means saved and requires reconciliation, never automatic retry. Linked returns and bill allocations, manual Purchase sundry discounts, and zero/exempt/nil treatment are not proven for new modes; existing Auto/exclusive supported flows remain. Cloud routes are not claimed deployed.</p>\n<p><strong>Mode payload examples</strong> (fragments; retain the route's company/year/date/reference/party/series/centre fields and use a matching configured native type):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\"taxCalculation\":\"auto\",\"pricingMode\":\"gstExclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 5% item\"},\"quantity\":1.25,\"rate\":10.10}]}\n{\"taxCalculation\":\"auto\",\"pricingMode\":\"gstInclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 18% item\"},\"quantity\":0.5,\"rate\":25.00}]}\n{\"taxCalculation\":\"manual\",\"pricingMode\":\"gstExclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 5% item\"},\"quantity\":1.25,\"rate\":10.10,\"amounts\":{\"taxableAmount\":12.62,\"cgst\":0.32,\"sgst\":0.32,\"igst\":0,\"amount\":13.26}}],\"totals\":{\"taxableAmount\":12.62,\"cgst\":0.32,\"sgst\":0.32,\"igst\":0,\"amount\":13.26}}\n{\"taxCalculation\":\"manual\",\"pricingMode\":\"gstInclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 18% item\"},\"quantity\":0.5,\"rate\":25.00,\"amounts\":{\"taxableAmount\":10.59,\"cgst\":0.96,\"sgst\":0.95,\"igst\":0,\"amount\":12.50}}],\"totals\":{\"taxableAmount\":10.59,\"cgst\":0.96,\"sgst\":0.95,\"igst\":0,\"amount\":12.50}}\n</code></pre>\n<p><strong>Mixed-rate Manual inclusive example:</strong> one 5% line may use a different configured tax category from an 18% line; sum every five amounts members exactly into totals. For central treatment replace both local components with IGST under the selected central native type. The one-paisa 18% example above shows the corrected CGST/SGST mapping. These are synthetic fragments, not live execution records.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n<h2 id=\"full-synthetic-gst-request-examples-local-only\">FULL synthetic GST request examples (Local only)</h2>\n<p>The raw Body tab above stays the minimal Auto/exclusive request. These separate complete bodies assume existing synthetic 5%/18% item tax categories, a matching item-wise native type, series, party and centre in the selected company/FY; replace fixture names and use a fresh reference before any send. <code>Local-TaxIncl.</code> must be configured with inclusive B13. Every line shares the voucher pricing mode. The amounts below are local CGST/SGST examples; for interstate treatment select the matching Central type and supply IGST instead. Return amounts remain positive in the request and BUSY reverses the postings. Do not infer Cloud Relay deployment from these Windows Local examples.</p>\n<p><strong>Auto + inclusive (synthetic FULL body):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstInclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-TaxIncl.\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic GST 18% Item\"\n      },\n      \"quantity\": 0.5,\n      \"rate\": 25\n    }\n  ]\n}\n</code></pre>\n<p><strong>Manual + exclusive (synthetic FULL body):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic GST 5% Item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0,\n        \"amount\": 13.26\n      }\n    }\n  ],\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0,\n    \"amount\": 13.26\n  }\n}\n</code></pre>\n<p><strong>Manual + inclusive (synthetic FULL body):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstInclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-TaxIncl.\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic GST 18% Item\"\n      },\n      \"quantity\": 0.5,\n      \"rate\": 25,\n      \"amounts\": {\n        \"taxableAmount\": 10.59,\n        \"cgst\": 0.96,\n        \"sgst\": 0.95,\n        \"igst\": 0,\n        \"amount\": 12.5\n      }\n    }\n  ],\n  \"totals\": {\n    \"taxableAmount\": 10.59,\n    \"cgst\": 0.96,\n    \"sgst\": 0.95,\n    \"igst\": 0,\n    \"amount\": 12.5\n  }\n}\n</code></pre>\n<p>The normal request's test requires 200 for a synchronous success; saved 400/409/422/502/504 examples are separate expected-refusal illustrations and do not constitute a successful create assertion. An explicit queue:true request requires 202 and must be polled for its final result.</p>\n<h2 id=\"optional-salesman-local-source-synthetic-examples\">Optional salesman (Local source; synthetic examples)</h2>\n<p><code>salesman</code> is an optional voucher-header object: <code>{\"code\":9701}</code> or <code>{\"name\":\"Synthetic Salesman\"}</code>, exactly one key. It resolves an existing active MasterType-19 Salesman in the selected company/FY, distinct from an account with the same name. BUSY must have effective voucher-level salesman reporting enabled for the selected series. The chosen identity tags the header and every item line; it does not calculate or post commission. Replace synthetic identity and voucher fixtures before any guarded send.</p>\n<p>Omit <code>salesman</code> or send <code>null</code> to retain native default behavior and the existing response shape. A verified explicit assignment adds <code>data.salesman:{code,name}</code> last in a synchronous 200 result or a completed queued result. HTTP 202 only accepts a durable job; inspect its final result before claiming BUSY persistence. The existing 200 example omits salesman; separate saved synthetic examples show assignment and explicit null.</p>\n<p>Exact pre-save refusals: <code>409 SALESMAN_CONFIGURATION_UNSUPPORTED</code> (effective setting), <code>409 SALESMAN_CONFIGURATION_CHANGED</code> (selected identity or frozen configuration changed), and <code>409 BUSY_SETTINGS_UNREADABLE</code> (requested settings unreadable), each with <code>metadata.error.field:\"salesman\"</code>. Unknown or wrong-master-type code/name is <code>422 MASTER_REFERENCE_NOT_FOUND</code>; a duplicate ambiguous name is <code>422 MASTER_REFERENCE_AMBIGUOUS</code>; inactive/unverifiable status is <code>400 INVALID_PARAMETER</code>. Invalid object shape/unknown keys are refused by strict JSON and reference validation. A refusal is not a successful create. Existing <code>502 BUSY_WRITE_UNVERIFIED</code> means a voucher was saved but independent proof differs (including possible salesman fields); <code>504 BUSY_WRITE_UNCERTAIN</code> may have saved. Preserve any known ID, reconcile BUSY and the write job before a new attempt. Never blind-retry or use a fresh reference to mask uncertainty. These examples are source-backed and synthetic, not installed-service or cloud acceptance.</p>\n<p>BUSY write admission (Local source, synthetic documentation): the business orderReference, company and FY own the durable Sales Order reference; X-Request-Id is a transport/queue ID and cannot bypass that ownership. 409 BUSY_WRITE_REFERENCE_IN_PROGRESS means an active prior writer owns it; 409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED means reconcile the original write read-only before any new submission; 503 BUSY_WRITE_ADMISSION_UNAVAILABLE means admission was not confirmed. Preserve the original reference and any known job/voucher ID. A 202 queue response only accepts the job, not the native voucher. After 502/504 or an unknown response, inspect the existing job/BUSY result; never automatically repost under a new request ID or reference. 409 BUSY_WRITE_TARGET_CHANGED refuses when the original company/FY/provider destination changed before native save. These are Local source contracts; synthetic examples are not installed-service or Cloud proof.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Installed public v0.0.30 predates this merged source; these are documentation examples only. Do not Send until a newer candidate with this source is installed and the target BUSY series is verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 3,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Synthetic colour: blue\",\n        \"\",\n        \"Synthetic size: large\"\n      ]\n    },\n    {\n      \"item\": {\n        \"code\": 1348\n      },\n      \"quantity\": 1,\n      \"rate\": 200\n    }\n  ],\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 3,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Synthetic colour: blue\",\n        \"\",\n        \"Synthetic size: large\"\n      ]\n    },\n    {\n      \"item\": {\n        \"code\": 1348\n      },\n      \"quantity\": 1,\n      \"rate\": 200\n    }\n  ],\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","sales-order-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"8a782463-0089-60dc-e39e-2d7df8d2e16d","name":"400 – rate less discount needs more than 2 decimals (refused before BUSY)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP0002\",\n  \"financialYear\": \"2026\",\n  \"orderReference\": \"WEB-ORDER-10046\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"code\": 7001 },\n  \"saleType\": { \"name\": \"Central-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"code\": 9401 }, \"quantity\": 2, \"rate\": 999.99, \"discountPercent\": 2 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create","description":"999.99 less 2 % = 979.9902 needs 4 decimals. BUSY keeps a sales order's price to 2 decimals (it stored 979.9902 as 979.99 in the installed acceptance on 2026-10-13), so AI Zeny refuses the line before anything reaches BUSY instead of letting it be rounded. Nothing is written. Fix the rate or discount so that the rate less the discount has at most 2 decimals (for example 1000 less 2 % = 980)."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"b4e19c07d2a65f38"},{"key":"Cache-Control","value":"no-store"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"lines[0]: the rate less discountPercent must come to at most 2 decimals (BUSY keeps the price to 2 decimals).\",\n      \"field\": \"lines[0].discountPercent\"\n    },\n    \"requestId\": \"b4e19c07d2a65f38\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"90a4540f-42e8-9e4c-baf6-f8e1cde75bcf","name":"200 – order created (local GST)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-POSTMAN ACC 01\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Synthetic colour: blue\", \"\", \"Synthetic size: large\"] },\n    { \"item\": { \"code\": 1348 }, \"quantity\": 1, \"rate\": 200 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-order-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `orderReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · operation `busy.sales-orders.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). The series must number automatically (`422 SALES_ORDER_SERIES_UNSUPPORTED`).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.sales-orders.create` (`POST /api/v1/sales-order-create`) creates one BUSY sales order through BUSY's own COM component on this PC. **Create only**: it never changes, cancels or deletes an order. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. Through the cloud: Windows relays it from source commit `6e3f9aa` onward with the master writes' rules, but the AI Zeny cloud has no `/v1/sales-order-create` route yet (2026-10-13), so use this Local request; see `docs/integration/Cloud-Sales-Order-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the order from the series. Your `orderReference` (1-60 characters) is stored in the order's narration and must be unique among the company's sales orders of the year. AI Zeny calculates each line's amount and GST from the item's tax category in BUSY (CGST + SGST for a local sale type, IGST for a central one); the sale type must take GST per item on tax-exclusive rates (for example `Local-ItemWise`, `Central-ItemWise`). BUSY's read-back and the saved rows are compared with what was sent before a success is answered.\n\n**2-decimal net rate.** BUSY keeps a sales order's price to **2 decimals**, so each line's rate less its discount (`rate × (1 − discountPercent / 100)`) must come to at most 2 decimals. Otherwise the line is refused with `400 INVALID_PARAMETER` (field `lines[i].discountPercent`) before anything reaches BUSY — it is never rounded. Example: 150 less 10 % = 135 is accepted; 999.99 less 2 % = 979.9902 is refused (installed acceptance 2026-10-13: BUSY stored it as 979.99).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `salesOrderReference` (current value) before each send — for example `AZPOC-SO-0NN`. The request is skipped without one.\n- Nothing is deleted automatically: a created test order stays in BUSY.\n- **Never retry blindly.** Sending the same `salesOrderReference` again is refused (`409 SALES_ORDER_REFERENCE_TAKEN`, `details.orderId`) if the first send saved, so a retry with the **same** reference can never make a duplicate. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `orderId`, `notFound`, `notChecked`) and check BUSY before anything else.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back differs (`details.orderId`, `details.mismatchedFields`): check it in BUSY.\n- One BUSY job at a time on the PC (shared with voucher PDFs and master writes), up to 2 minutes: give the request a long timeout.\n\n**Body:** `companyCode`, `financialYear`, `orderReference`, `date` (`YYYY-MM-DD` in the year), `voucherSeries` (optional when only one), `customer`, `saleType`, `materialCenter` (each `{\"code\": n}` or `{\"name\": \"…\"}`), `lines` (1-100: `item`, `quantity` > 0 with ≤ 3 decimals, `rate` ≥ 0 with ≤ 2 decimals, optional `discountPercent` 0-100 with ≤ 2 decimals; rate less discount ≤ 2 decimals; optional `description`, see below). Amounts, tax, order numbers and any other member are refused. Body up to 64 KiB.\n\n**Sets:** `salesOrderId` on success. Public guide: `docs/public/api/sales-order-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. A Host before 2026-10-19 refuses the member (`400 BAD_REQUEST`). Public guide: `docs/public/api/line-descriptions.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"3f2a9c1e7b4d4e0a"},{"key":"Cache-Control","value":"no-store"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"orderId\": 8801,\n    \"orderNumber\": \"SO-25\",\n    \"orderReference\": \"WEB-ORDER-10045\",\n    \"date\": \"2026-10-13\",\n    \"voucherSeries\": { \"code\": 261, \"name\": \"Main\" },\n    \"customer\": { \"code\": 7001, \"name\": \"Synthetic Traders\" },\n    \"saleType\": { \"code\": 1223, \"name\": \"Local-ItemWise\" },\n    \"taxation\": \"local\",\n    \"materialCenter\": { \"code\": 201, \"name\": \"Main Store\" },\n    \"lines\": [\n      { \"lineNumber\": 1, \"item\": { \"code\": 9401, \"name\": \"Synthetic Item\" }, \"unit\": \"Pcs.\", \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10, \"netRate\": 135, \"taxableAmount\": 405, \"cgst\": 24.3, \"sgst\": 24.3, \"igst\": 0, \"taxAmount\": 48.6, \"amount\": 453.6 },\n      { \"lineNumber\": 2, \"item\": { \"code\": 9401, \"name\": \"Synthetic Item\" }, \"unit\": \"Pcs.\", \"quantity\": 1, \"rate\": 200, \"discountPercent\": 0, \"netRate\": 200, \"taxableAmount\": 200, \"cgst\": 12, \"sgst\": 12, \"igst\": 0, \"taxAmount\": 24, \"amount\": 224 }\n    ],\n    \"totals\": { \"quantity\": 4, \"taxableAmount\": 605, \"taxAmount\": 72.6, \"amount\": 677.6 }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-orders.create\",\n    \"requestId\": \"3f2a9c1e7b4d4e0a\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 2,\n    \"verification\": [\"busyReadBack\", \"savedRows\"],\n    \"elapsedMs\": 5120,\n    \"executedAt\": \"2026-10-13T07:30:00+00:00\"\n  }\n}"},{"id":"a2a66b8e-2765-34bb-9c83-92985f588de5","name":"409 – reference already held (safe retry)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-POSTMAN ACC 01\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Synthetic colour: blue\", \"\", \"Synthetic size: large\"] },\n    { \"item\": { \"code\": 1348 }, \"quantity\": 1, \"rate\": 200 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-order-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `orderReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · operation `busy.sales-orders.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). The series must number automatically (`422 SALES_ORDER_SERIES_UNSUPPORTED`).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.sales-orders.create` (`POST /api/v1/sales-order-create`) creates one BUSY sales order through BUSY's own COM component on this PC. **Create only**: it never changes, cancels or deletes an order. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. Through the cloud: Windows relays it from source commit `6e3f9aa` onward with the master writes' rules, but the AI Zeny cloud has no `/v1/sales-order-create` route yet (2026-10-13), so use this Local request; see `docs/integration/Cloud-Sales-Order-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the order from the series. Your `orderReference` (1-60 characters) is stored in the order's narration and must be unique among the company's sales orders of the year. AI Zeny calculates each line's amount and GST from the item's tax category in BUSY (CGST + SGST for a local sale type, IGST for a central one); the sale type must take GST per item on tax-exclusive rates (for example `Local-ItemWise`, `Central-ItemWise`). BUSY's read-back and the saved rows are compared with what was sent before a success is answered.\n\n**2-decimal net rate.** BUSY keeps a sales order's price to **2 decimals**, so each line's rate less its discount (`rate × (1 − discountPercent / 100)`) must come to at most 2 decimals. Otherwise the line is refused with `400 INVALID_PARAMETER` (field `lines[i].discountPercent`) before anything reaches BUSY — it is never rounded. Example: 150 less 10 % = 135 is accepted; 999.99 less 2 % = 979.9902 is refused (installed acceptance 2026-10-13: BUSY stored it as 979.99).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `salesOrderReference` (current value) before each send — for example `AZPOC-SO-0NN`. The request is skipped without one.\n- Nothing is deleted automatically: a created test order stays in BUSY.\n- **Never retry blindly.** Sending the same `salesOrderReference` again is refused (`409 SALES_ORDER_REFERENCE_TAKEN`, `details.orderId`) if the first send saved, so a retry with the **same** reference can never make a duplicate. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `orderId`, `notFound`, `notChecked`) and check BUSY before anything else.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back differs (`details.orderId`, `details.mismatchedFields`): check it in BUSY.\n- One BUSY job at a time on the PC (shared with voucher PDFs and master writes), up to 2 minutes: give the request a long timeout.\n\n**Body:** `companyCode`, `financialYear`, `orderReference`, `date` (`YYYY-MM-DD` in the year), `voucherSeries` (optional when only one), `customer`, `saleType`, `materialCenter` (each `{\"code\": n}` or `{\"name\": \"…\"}`), `lines` (1-100: `item`, `quantity` > 0 with ≤ 3 decimals, `rate` ≥ 0 with ≤ 2 decimals, optional `discountPercent` 0-100 with ≤ 2 decimals; rate less discount ≤ 2 decimals; optional `description`, see below). Amounts, tax, order numbers and any other member are refused. Body up to 64 KiB.\n\n**Sets:** `salesOrderId` on success. Public guide: `docs/public/api/sales-order-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. A Host before 2026-10-19 refuses the member (`400 BAD_REQUEST`). Public guide: `docs/public/api/line-descriptions.md`."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"7c1d0e5a9b2f4c33"},{"key":"Cache-Control","value":"no-store"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SALES_ORDER_REFERENCE_TAKEN\",\n      \"message\": \"A sales order of this company and financial year already holds this orderReference. A create never changes an existing order; if your earlier call saved it, metadata.error.details.orderId names it.\",\n      \"field\": \"orderReference\",\n      \"details\": { \"orderId\": 8801 }\n    },\n    \"requestId\": \"7c1d0e5a9b2f4c33\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"4830bc14-a288-678b-a77a-b50fbf08ba98","name":"422 – item tax category not one plain GST rate","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-POSTMAN ACC 01\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Synthetic colour: blue\", \"\", \"Synthetic size: large\"] },\n    { \"item\": { \"code\": 1348 }, \"quantity\": 1, \"rate\": 200 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-order-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `orderReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · operation `busy.sales-orders.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). The series must number automatically (`422 SALES_ORDER_SERIES_UNSUPPORTED`).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.sales-orders.create` (`POST /api/v1/sales-order-create`) creates one BUSY sales order through BUSY's own COM component on this PC. **Create only**: it never changes, cancels or deletes an order. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. Through the cloud: Windows relays it from source commit `6e3f9aa` onward with the master writes' rules, but the AI Zeny cloud has no `/v1/sales-order-create` route yet (2026-10-13), so use this Local request; see `docs/integration/Cloud-Sales-Order-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the order from the series. Your `orderReference` (1-60 characters) is stored in the order's narration and must be unique among the company's sales orders of the year. AI Zeny calculates each line's amount and GST from the item's tax category in BUSY (CGST + SGST for a local sale type, IGST for a central one); the sale type must take GST per item on tax-exclusive rates (for example `Local-ItemWise`, `Central-ItemWise`). BUSY's read-back and the saved rows are compared with what was sent before a success is answered.\n\n**2-decimal net rate.** BUSY keeps a sales order's price to **2 decimals**, so each line's rate less its discount (`rate × (1 − discountPercent / 100)`) must come to at most 2 decimals. Otherwise the line is refused with `400 INVALID_PARAMETER` (field `lines[i].discountPercent`) before anything reaches BUSY — it is never rounded. Example: 150 less 10 % = 135 is accepted; 999.99 less 2 % = 979.9902 is refused (installed acceptance 2026-10-13: BUSY stored it as 979.99).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `salesOrderReference` (current value) before each send — for example `AZPOC-SO-0NN`. The request is skipped without one.\n- Nothing is deleted automatically: a created test order stays in BUSY.\n- **Never retry blindly.** Sending the same `salesOrderReference` again is refused (`409 SALES_ORDER_REFERENCE_TAKEN`, `details.orderId`) if the first send saved, so a retry with the **same** reference can never make a duplicate. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `orderId`, `notFound`, `notChecked`) and check BUSY before anything else.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back differs (`details.orderId`, `details.mismatchedFields`): check it in BUSY.\n- One BUSY job at a time on the PC (shared with voucher PDFs and master writes), up to 2 minutes: give the request a long timeout.\n\n**Body:** `companyCode`, `financialYear`, `orderReference`, `date` (`YYYY-MM-DD` in the year), `voucherSeries` (optional when only one), `customer`, `saleType`, `materialCenter` (each `{\"code\": n}` or `{\"name\": \"…\"}`), `lines` (1-100: `item`, `quantity` > 0 with ≤ 3 decimals, `rate` ≥ 0 with ≤ 2 decimals, optional `discountPercent` 0-100 with ≤ 2 decimals; rate less discount ≤ 2 decimals; optional `description`, see below). Amounts, tax, order numbers and any other member are refused. Body up to 64 KiB.\n\n**Sets:** `salesOrderId` on success. Public guide: `docs/public/api/sales-order-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. A Host before 2026-10-19 refuses the member (`400 BAD_REQUEST`). Public guide: `docs/public/api/line-descriptions.md`."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"a90b44f2c6e81d07","key":"X-Request-Id"},{"value":"no-store","key":"Cache-Control"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SALES_ORDER_TAX_UNSUPPORTED\",\n      \"message\": \"This item's tax category in BUSY is not one GST rate AI Zeny calculates (a taxable category with one CGST, SGST and IGST rate and no cess or other rate). Set a GST tax category on the item in BUSY.\",\n      \"field\": \"lines[1].item\"\n    },\n    \"requestId\": \"a90b44f2c6e81d07\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"9af73955-2ae5-ee1a-f9de-25d1a483dd48","name":"504 – uncertain, reconciled (found): do not resend with a new reference","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-POSTMAN ACC 01\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Synthetic colour: blue\", \"\", \"Synthetic size: large\"] },\n    { \"item\": { \"code\": 1348 }, \"quantity\": 1, \"rate\": 200 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-order-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `orderReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · operation `busy.sales-orders.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). The series must number automatically (`422 SALES_ORDER_SERIES_UNSUPPORTED`).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.sales-orders.create` (`POST /api/v1/sales-order-create`) creates one BUSY sales order through BUSY's own COM component on this PC. **Create only**: it never changes, cancels or deletes an order. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. Through the cloud: Windows relays it from source commit `6e3f9aa` onward with the master writes' rules, but the AI Zeny cloud has no `/v1/sales-order-create` route yet (2026-10-13), so use this Local request; see `docs/integration/Cloud-Sales-Order-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the order from the series. Your `orderReference` (1-60 characters) is stored in the order's narration and must be unique among the company's sales orders of the year. AI Zeny calculates each line's amount and GST from the item's tax category in BUSY (CGST + SGST for a local sale type, IGST for a central one); the sale type must take GST per item on tax-exclusive rates (for example `Local-ItemWise`, `Central-ItemWise`). BUSY's read-back and the saved rows are compared with what was sent before a success is answered.\n\n**2-decimal net rate.** BUSY keeps a sales order's price to **2 decimals**, so each line's rate less its discount (`rate × (1 − discountPercent / 100)`) must come to at most 2 decimals. Otherwise the line is refused with `400 INVALID_PARAMETER` (field `lines[i].discountPercent`) before anything reaches BUSY — it is never rounded. Example: 150 less 10 % = 135 is accepted; 999.99 less 2 % = 979.9902 is refused (installed acceptance 2026-10-13: BUSY stored it as 979.99).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `salesOrderReference` (current value) before each send — for example `AZPOC-SO-0NN`. The request is skipped without one.\n- Nothing is deleted automatically: a created test order stays in BUSY.\n- **Never retry blindly.** Sending the same `salesOrderReference` again is refused (`409 SALES_ORDER_REFERENCE_TAKEN`, `details.orderId`) if the first send saved, so a retry with the **same** reference can never make a duplicate. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `orderId`, `notFound`, `notChecked`) and check BUSY before anything else.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back differs (`details.orderId`, `details.mismatchedFields`): check it in BUSY.\n- One BUSY job at a time on the PC (shared with voucher PDFs and master writes), up to 2 minutes: give the request a long timeout.\n\n**Body:** `companyCode`, `financialYear`, `orderReference`, `date` (`YYYY-MM-DD` in the year), `voucherSeries` (optional when only one), `customer`, `saleType`, `materialCenter` (each `{\"code\": n}` or `{\"name\": \"…\"}`), `lines` (1-100: `item`, `quantity` > 0 with ≤ 3 decimals, `rate` ≥ 0 with ≤ 2 decimals, optional `discountPercent` 0-100 with ≤ 2 decimals; rate less discount ≤ 2 decimals; optional `description`, see below). Amounts, tax, order numbers and any other member are refused. Body up to 64 KiB.\n\n**Sets:** `salesOrderId` on success. Public guide: `docs/public/api/sales-order-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. A Host before 2026-10-19 refuses the member (`400 BAD_REQUEST`). Public guide: `docs/public/api/line-descriptions.md`."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"52e8d17b0fa34c69"},{"key":"Cache-Control","value":"no-store"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"BUSY stopped while saving the sales order; a sales order with this orderReference exists now (metadata.error.details.orderId). Check it in BUSY; do not send it again.\",\n      \"details\": { \"orderId\": 8802, \"reconciliation\": \"found\" }\n    },\n    \"requestId\": \"52e8d17b0fa34c69\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"ab1c2d02-02a4-9242-9d5f-33bfef5a14ba","name":"422 — description position beyond the series' lines (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-POSTMAN ACC 01\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Synthetic colour: blue\", \"\", \"Synthetic size: large\"] },\n    { \"item\": { \"code\": 1348 }, \"quantity\": 1, \"rate\": 200 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-order-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `orderReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · operation `busy.sales-orders.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). The series must number automatically (`422 SALES_ORDER_SERIES_UNSUPPORTED`).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.sales-orders.create` (`POST /api/v1/sales-order-create`) creates one BUSY sales order through BUSY's own COM component on this PC. **Create only**: it never changes, cancels or deletes an order. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. Through the cloud: Windows relays it from source commit `6e3f9aa` onward with the master writes' rules, but the AI Zeny cloud has no `/v1/sales-order-create` route yet (2026-10-13), so use this Local request; see `docs/integration/Cloud-Sales-Order-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the order from the series. Your `orderReference` (1-60 characters) is stored in the order's narration and must be unique among the company's sales orders of the year. AI Zeny calculates each line's amount and GST from the item's tax category in BUSY (CGST + SGST for a local sale type, IGST for a central one); the sale type must take GST per item on tax-exclusive rates (for example `Local-ItemWise`, `Central-ItemWise`). BUSY's read-back and the saved rows are compared with what was sent before a success is answered.\n\n**2-decimal net rate.** BUSY keeps a sales order's price to **2 decimals**, so each line's rate less its discount (`rate × (1 − discountPercent / 100)`) must come to at most 2 decimals. Otherwise the line is refused with `400 INVALID_PARAMETER` (field `lines[i].discountPercent`) before anything reaches BUSY — it is never rounded. Example: 150 less 10 % = 135 is accepted; 999.99 less 2 % = 979.9902 is refused (installed acceptance 2026-10-13: BUSY stored it as 979.99).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `salesOrderReference` (current value) before each send — for example `AZPOC-SO-0NN`. The request is skipped without one.\n- Nothing is deleted automatically: a created test order stays in BUSY.\n- **Never retry blindly.** Sending the same `salesOrderReference` again is refused (`409 SALES_ORDER_REFERENCE_TAKEN`, `details.orderId`) if the first send saved, so a retry with the **same** reference can never make a duplicate. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `orderId`, `notFound`, `notChecked`) and check BUSY before anything else.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back differs (`details.orderId`, `details.mismatchedFields`): check it in BUSY.\n- One BUSY job at a time on the PC (shared with voucher PDFs and master writes), up to 2 minutes: give the request a long timeout.\n\n**Body:** `companyCode`, `financialYear`, `orderReference`, `date` (`YYYY-MM-DD` in the year), `voucherSeries` (optional when only one), `customer`, `saleType`, `materialCenter` (each `{\"code\": n}` or `{\"name\": \"…\"}`), `lines` (1-100: `item`, `quantity` > 0 with ≤ 3 decimals, `rate` ≥ 0 with ≤ 2 decimals, optional `discountPercent` 0-100 with ≤ 2 decimals; rate less discount ≤ 2 decimals; optional `description`, see below). Amounts, tax, order numbers and any other member are refused. Body up to 64 KiB.\n\n**Sets:** `salesOrderId` on success. Public guide: `docs/public/api/sales-order-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. A Host before 2026-10-19 refuses the member (`400 BAD_REQUEST`). Public guide: `docs/public/api/line-descriptions.md`."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-orders.create\",\n    \"requestId\": \"00000000000000000000000000000000\",\n    \"error\": {\n      \"code\": \"DESCRIPTION_LINE_NOT_ALLOWED\",\n      \"message\": \"This voucher series allows 4 description lines per item line in BUSY, and lines[0].description[4] is beyond it; nothing was saved. Send at most 4 (an empty position counts), or raise the series' number of description lines in BUSY.\",\n      \"field\": \"lines[0].description[4]\"\n    }\n  }\n}"},{"id":"6921a74b-570d-b5a4-5a45-d4cd3c2650be","name":"409 – GST_CONFIGURATION_CHANGED (before save)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic 5% item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0,\n        \"amount\": 13.26\n      }\n    }\n  ],\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0,\n    \"amount\": 13.26\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"GST_CONFIGURATION_CHANGED\",\n      \"message\": \"BUSY's selected GST or voucher-series configuration changed while this request was being prepared. Read it again and submit a new request.\"\n    }\n  }\n}"},{"id":"e438a74d-99ec-81ee-1789-3720d2de5fea","name":"422 – GST_AMOUNTS_INVALID (manual treatment)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic 5% item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0.05,\n        \"amount\": 13.31\n      }\n    }\n  ],\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0.05,\n    \"amount\": 13.31\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"GST_AMOUNTS_INVALID\",\n      \"message\": \"Manual GST amounts conflict with the selected tax rate or local/central treatment.\"\n    }\n  }\n}"},{"id":"20bce2c0-6db2-03fa-5ea2-bb35cc929e87","name":"502 – BUSY_WRITE_UNVERIFIED (saved; reconcile)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic 5% item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0,\n        \"amount\": 13.26\n      }\n    }\n  ],\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0,\n    \"amount\": 13.26\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create"},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNVERIFIED\",\n      \"message\": \"BUSY saved the voucher but read-back differs; inspect the saved reference and do not resend.\"\n    }\n  }\n}"},{"id":"163f2fab-c05f-8645-77a9-832ab7620f4b","name":"400 – INVALID_PARAMETER (Manual breakdown missing)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 3,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Synthetic colour: blue\",\n        \"\",\n        \"Synthetic size: large\"\n      ]\n    },\n    {\n      \"item\": {\n        \"code\": 1348\n      },\n      \"quantity\": 1,\n      \"rate\": 200\n    }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"Manual GST breakdown is required for every line and document totals.\"\n    }\n  }\n}"},{"id":"ebc42385-9fd8-60eb-4cc9-add66b0053c3","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 3,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Synthetic colour: blue\",\n        \"\",\n        \"Synthetic size: large\"\n      ]\n    },\n    {\n      \"item\": {\n        \"code\": 1348\n      },\n      \"quantity\": 1,\n      \"rate\": 200\n    }\n  ],\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"synthetic-queue-001"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-orders.create\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"},{"id":"bd583ed6-5943-a415-48f1-9946da8ecd7f","name":"200 – salesman assigned (synthetic Local; code)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 3,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Synthetic colour: blue\",\n        \"\",\n        \"Synthetic size: large\"\n      ]\n    },\n    {\n      \"item\": {\n        \"code\": 1348\n      },\n      \"quantity\": 1,\n      \"rate\": 200\n    }\n  ],\n  \"salesman\": {\n    \"code\": 9701\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"orderId\": 8801,\n    \"orderNumber\": \"SO-25\",\n    \"orderReference\": \"WEB-ORDER-10045\",\n    \"date\": \"2026-10-13\",\n    \"voucherSeries\": {\n      \"code\": 261,\n      \"name\": \"Main\"\n    },\n    \"customer\": {\n      \"code\": 7001,\n      \"name\": \"Synthetic Traders\"\n    },\n    \"saleType\": {\n      \"code\": 1223,\n      \"name\": \"Local-ItemWise\"\n    },\n    \"taxation\": \"local\",\n    \"materialCenter\": {\n      \"code\": 201,\n      \"name\": \"Main Store\"\n    },\n    \"lines\": [\n      {\n        \"lineNumber\": 1,\n        \"item\": {\n          \"code\": 9401,\n          \"name\": \"Synthetic Item\"\n        },\n        \"unit\": \"Pcs.\",\n        \"quantity\": 3,\n        \"rate\": 150,\n        \"discountPercent\": 10,\n        \"netRate\": 135,\n        \"taxableAmount\": 405,\n        \"cgst\": 24.3,\n        \"sgst\": 24.3,\n        \"igst\": 0,\n        \"taxAmount\": 48.6,\n        \"amount\": 453.6\n      },\n      {\n        \"lineNumber\": 2,\n        \"item\": {\n          \"code\": 9401,\n          \"name\": \"Synthetic Item\"\n        },\n        \"unit\": \"Pcs.\",\n        \"quantity\": 1,\n        \"rate\": 200,\n        \"discountPercent\": 0,\n        \"netRate\": 200,\n        \"taxableAmount\": 200,\n        \"cgst\": 12,\n        \"sgst\": 12,\n        \"igst\": 0,\n        \"taxAmount\": 24,\n        \"amount\": 224\n      }\n    ],\n    \"totals\": {\n      \"quantity\": 4,\n      \"taxableAmount\": 605,\n      \"taxAmount\": 72.6,\n      \"amount\": 677.6\n    },\n    \"salesman\": {\n      \"code\": 9701,\n      \"name\": \"Synthetic Salesman\"\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-orders.create\",\n    \"requestId\": \"3f2a9c1e7b4d4e0a\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 2,\n    \"verification\": [\n      \"busyReadBack\",\n      \"savedRows\"\n    ],\n    \"elapsedMs\": 5120,\n    \"executedAt\": \"2026-10-13T07:30:00+00:00\"\n  }\n}"},{"id":"53d1285e-c6e7-cd41-59ae-4dd9bd12b7ec","name":"200 – salesman explicitly null (synthetic Local; native default)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 3,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Synthetic colour: blue\",\n        \"\",\n        \"Synthetic size: large\"\n      ]\n    },\n    {\n      \"item\": {\n        \"code\": 1348\n      },\n      \"quantity\": 1,\n      \"rate\": 200\n    }\n  ],\n  \"salesman\": null\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"orderId\": 8801,\n    \"orderNumber\": \"SO-25\",\n    \"orderReference\": \"WEB-ORDER-10045\",\n    \"date\": \"2026-10-13\",\n    \"voucherSeries\": {\n      \"code\": 261,\n      \"name\": \"Main\"\n    },\n    \"customer\": {\n      \"code\": 7001,\n      \"name\": \"Synthetic Traders\"\n    },\n    \"saleType\": {\n      \"code\": 1223,\n      \"name\": \"Local-ItemWise\"\n    },\n    \"taxation\": \"local\",\n    \"materialCenter\": {\n      \"code\": 201,\n      \"name\": \"Main Store\"\n    },\n    \"lines\": [\n      {\n        \"lineNumber\": 1,\n        \"item\": {\n          \"code\": 9401,\n          \"name\": \"Synthetic Item\"\n        },\n        \"unit\": \"Pcs.\",\n        \"quantity\": 3,\n        \"rate\": 150,\n        \"discountPercent\": 10,\n        \"netRate\": 135,\n        \"taxableAmount\": 405,\n        \"cgst\": 24.3,\n        \"sgst\": 24.3,\n        \"igst\": 0,\n        \"taxAmount\": 48.6,\n        \"amount\": 453.6\n      },\n      {\n        \"lineNumber\": 2,\n        \"item\": {\n          \"code\": 9401,\n          \"name\": \"Synthetic Item\"\n        },\n        \"unit\": \"Pcs.\",\n        \"quantity\": 1,\n        \"rate\": 200,\n        \"discountPercent\": 0,\n        \"netRate\": 200,\n        \"taxableAmount\": 200,\n        \"cgst\": 12,\n        \"sgst\": 12,\n        \"igst\": 0,\n        \"taxAmount\": 24,\n        \"amount\": 224\n      }\n    ],\n    \"totals\": {\n      \"quantity\": 4,\n      \"taxableAmount\": 605,\n      \"taxAmount\": 72.6,\n      \"amount\": 677.6\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-orders.create\",\n    \"requestId\": \"3f2a9c1e7b4d4e0a\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 2,\n    \"verification\": [\n      \"busyReadBack\",\n      \"savedRows\"\n    ],\n    \"elapsedMs\": 5120,\n    \"executedAt\": \"2026-10-13T07:30:00+00:00\"\n  }\n}"},{"id":"ce21399c-4595-7d33-db5b-a549a003b428","name":"409 – SALESMAN_CONFIGURATION_UNSUPPORTED (synthetic; nothing saved)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 3,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Synthetic colour: blue\",\n        \"\",\n        \"Synthetic size: large\"\n      ]\n    },\n    {\n      \"item\": {\n        \"code\": 1348\n      },\n      \"quantity\": 1,\n      \"rate\": 200\n    }\n  ],\n  \"salesman\": {\n    \"code\": 9701\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SALESMAN_CONFIGURATION_UNSUPPORTED\",\n      \"message\": \"The company does not support the requested voucher-level salesman assignment.\",\n      \"field\": \"salesman\"\n    }\n  }\n}"},{"id":"e86945d8-3dfc-da8e-3ca5-81baa43bdfda","name":"409 – SALESMAN_CONFIGURATION_CHANGED (synthetic; nothing saved)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 3,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Synthetic colour: blue\",\n        \"\",\n        \"Synthetic size: large\"\n      ]\n    },\n    {\n      \"item\": {\n        \"code\": 1348\n      },\n      \"quantity\": 1,\n      \"rate\": 200\n    }\n  ],\n  \"salesman\": {\n    \"code\": 9701\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SALESMAN_CONFIGURATION_CHANGED\",\n      \"message\": \"The salesman or its configuration changed before save; nothing was saved.\",\n      \"field\": \"salesman\"\n    }\n  }\n}"},{"id":"feffb4ec-dc09-cbea-e950-ff1486d746b7","name":"422 – MASTER_REFERENCE_NOT_FOUND salesman (synthetic; nothing saved)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 3,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Synthetic colour: blue\",\n        \"\",\n        \"Synthetic size: large\"\n      ]\n    },\n    {\n      \"item\": {\n        \"code\": 1348\n      },\n      \"quantity\": 1,\n      \"rate\": 200\n    }\n  ],\n  \"salesman\": {\n    \"code\": 999999\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"MASTER_REFERENCE_NOT_FOUND\",\n      \"message\": \"No salesman with that code or name exists in this company and financial year.\",\n      \"field\": \"salesman\"\n    }\n  }\n}"},{"id":"cc8fa5b0-3ee0-4056-b6c8-1559d42ff022","name":"409 – BUSY_WRITE_REFERENCE_IN_PROGRESS (synthetic; no repost)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/sales-order-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"metadata\":{\"error\":{\"code\":\"BUSY_WRITE_REFERENCE_IN_PROGRESS\",\"field\":\"orderReference\",\"message\":\"Another write owns this business reference. Wait for its result; do not resend under a different request ID.\"}},\"success\":false,\"data\":null}"},{"id":"a62d1af6-d32e-466f-8dc8-623de6894165","name":"409 - BUSY_WRITE_REFERENCE_REVIEW_REQUIRED (synthetic; before save)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/sales-order-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"BUSY_WRITE_REFERENCE_REVIEW_REQUIRED\",\"field\":\"orderReference\",\"message\":\"An earlier write with this business reference needs read-only reconciliation. Do not repost it. Use its existing job/result and retain the original reference.\"}}}"},{"id":"fe52494d-c78c-478e-995d-e2a0cde4e9fc","name":"503 - BUSY_WRITE_ADMISSION_UNAVAILABLE (synthetic; review prior result)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/sales-order-create"},"status":"Service Unavailable","code":503,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"metadata\":{\"error\":{\"message\":\"Durable write admission could not be confirmed. Retain the reference and review the previous result.\",\"code\":\"BUSY_WRITE_ADMISSION_UNAVAILABLE\"}},\"success\":false,\"data\":null}"},{"id":"b15cc48d-0367-4a88-87c1-62dcd0915d75","name":"409 - BUSY_WRITE_TARGET_CHANGED (synthetic; before save)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/sales-order-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"BUSY_WRITE_TARGET_CHANGED\",\"message\":\"The BUSY destination or its permissions changed before helper execution; nothing was saved.\"}}}"}],"_postman_id":"9c52eabc-ed2c-4599-ff04-f787702bb271"},{"name":"⚠ BUSY sales invoice – create (writes to BUSY)","id":"a8cc6684-520c-a2f6-2416-345f629263ff","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 2, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Postman test line\"] },\n    { \"item\": { \"name\": \"Parle G\" }, \"quantity\": 2.5, \"rate\": 20.10 }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/sales-invoice-create</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>⚠ Writes to BUSY</strong> (Development Local Send requires no separate confirmation)\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>invoiceReference</code>, <code>date</code>, <code>customer</code>, <code>saleType</code>, <code>materialCenter</code>, <code>lines</code>, <code>lines[].item</code>, <code>lines[].quantity</code>, <code>lines[].rate</code> · operation <code>busy.sales-invoices.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq). Before the save AI Zeny reads BUSY's settings: the series must keep separate billing details (<code>422 BUSY_SETTING_REQUIRED</code>, field <code>voucherSeries</code>), a bill-by-bill customer without <code>dueDate</code> needs \"Auto Create Party References in Sales Voucher\" (field <code>dueDate</code>), and the series must number automatically (<code>422 SALES_INVOICE_SERIES_UNSUPPORTED</code>); <code>502 BUSY_SETTINGS_UNREADABLE</code> when BUSY's configuration cannot be read.</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books. Run manually, one at a time.</strong> <code>busy.sales-invoices.create</code> (<code>POST /api/v1/sales-invoice-create</code>) creates one BUSY sales invoice through BUSY's own COM component on this PC. <strong>Create only</strong>: it never changes, cancels or deletes an invoice, never converts a sales order, and never generates an e-invoice or e-way bill. <strong>SQL Server companies with a SQL login, or Access companies</strong>. Never run from scripts. <strong>Status:</strong> installed service-account acceptance passed on 2026-10-14 (COMP0002 / 2026). <strong>Through the cloud: not available</strong> — Windows relays it with the write rules (same organization token), but the AI Zeny cloud has no <code>/v1/sales-invoice-create</code> route yet (<code>404</code>, 2026-10-14), so there is no Cloud Relay request for it; see <code>docs/integration/Cloud-Sales-Invoice-Relay-Handoff.md</code>.</p>\n<p><strong>How it works.</strong> BUSY numbers the invoice from the series and derives the ledger lines (customer, sales account, CGST/SGST or IGST accounts) and the customer's bill reference (due on the date plus the customer's credit days). Your <code>invoiceReference</code> (1-60) is stored in the first narration and must be unique among the company's sales invoices of the year; <code>narration</code> goes to the second narration. AI Zeny calculates each line's amount and GST from the item's tax category (exact decimals, half away from zero, <strong>no round-off</strong>), fills the billing details from the customer and the MRP from the item as BUSY's window does, and compares BUSY's read-back and the saved rows with what was sent before answering.</p>\n<p><strong>Masters are never created.</strong> BUSY's import would create a master for an unknown name, so every customer, item, unit, series, sale type and godown must already exist (<code>422 MASTER_REFERENCE_NOT_FOUND</code>) and is checked again with BUSY's own lookup just before the save (<code>409 SALES_INVOICE_MASTER_CHANGED</code>).</p>\n<p><strong>Serial-number, batch and parameter items are refused</strong> (<code>422 SALES_INVOICE_ITEM_UNSUPPORTED</code>, the message names which): AI Zeny reads the item's own settings in BUSY (serial-number type, batch type, parameter-wise stock), so an item set up for tracking is refused even before any details were recorded, and also refuses an item that already has serial-number or parameter records. BUSY's own import would save such an invoice without the details. Stock below zero and a customer past its credit limit are <strong>not</strong> refused (BUSY's own behaviour).</p>\n<p><strong>Optional:</strong> <code>dueDate</code> (<code>YYYY-MM-DD</code>; the bill reference is then named by <code>invoiceReference</code>, ≤ 25 characters, bill-by-bill customers only), <code>billing</code> {<code>name</code>, <code>address1</code>-<code>address4</code>, <code>mobile</code>, <code>email</code>} (GSTIN, PAN and state stay the customer's), <code>lines[].mrp</code>, <code>lines[].description</code> (1-10 positions × 1-40, see below), <code>narration</code> (1-94), <code>transport</code>, <code>grNumber</code>, <code>vehicleNumber</code>, <code>station</code> (1-30), <code>voucherSeries</code> (when the company has more than one). Auto refuses explicit amounts/totals; Manual follows the GST billing-mode contract. Invoice numbers, ledger lines, XML and <code>tmp…</code> members are refused. Body up to 128 KiB.</p>\n<p><strong>Safe test guidance</strong></p>\n<ul>\n<li>Select a development-test <code>companyCode</code> (<code>COMP0002</code> / FY 2026 in this environment; use <code>COMP0001</code> for Access tests). With <code>autoVoucherReferences=yes</code>, each Local Send generates and stores a fresh 25-character synthetic <code>salesInvoiceReference</code>. Set that switch to <code>no</code> to supply your own unique reference. Do not reuse <code>AZPOC-SI-…</code> or <code>AZSVC-SI-…</code> (earlier test records).</li>\n<li>Nothing is deleted automatically: a created test invoice stays in BUSY.</li>\n<li><strong>Never retry blindly.</strong> Automatic references change on each Send, so another Send can create another voucher; reconcile an uncertain result first. Sending the same <code>salesInvoiceReference</code> again is refused (<code>409 SALES_INVOICE_REFERENCE_TAKEN</code>, <code>details.invoiceId</code>) if the first send saved. After <code>504 BUSY_WRITE_UNCERTAIN</code>, read <code>metadata.error.details.reconciliation</code> (<code>found</code> + <code>invoiceId</code>, <code>notFound</code>, <code>notChecked</code>) and check BUSY first.</li>\n<li><code>502 BUSY_WRITE_UNVERIFIED</code> means BUSY <strong>did</strong> save but its read-back differs (<code>details.invoiceId</code>, <code>details.mismatchedFields</code>).</li>\n<li>One BUSY job at a time on the PC (shared with voucher PDFs, orders and master writes), up to 2 minutes: give the request a long timeout.</li>\n</ul>\n<p><strong>Sets:</strong> <code>salesInvoiceId</code> on success (usable as <code>voucherId</code> in the Sales invoice PDF request). Public guide: <code>docs/public/api/sales-invoice-create.md</code>.</p>\n<p><strong>Line descriptions (owner acceptance 2026-10-19; <code>docs/features/BUSY-Voucher-Line-Descriptions.md</code>):</strong> <code>lines[].description</code> is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; <code>\"\"</code> or <code>null</code> keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise <code>422 BUSY_SETTING_REQUIRED</code> (<code>lines[i].description</code>) or <code>422 DESCRIPTION_LINE_NOT_ALLOWED</code> (<code>lines[i].description[n]</code>), nothing saved. SQL Server companies take Latin-1 characters only (<code>400</code>, before BUSY); Access companies any text. The answer's lines carry <code>description</code> as saved. Public guide: <code>docs/public/api/line-descriptions.md</code>.</p>\n<p><strong>GST billing modes (bounded internal 0.0.15 candidate accepted 2026-10-20 on Access and SQL Server; 0.0.16 release smoke was narrower):</strong> Optional <code>taxCalculation</code> is <code>auto</code> (default) or <code>manual</code>; optional <code>pricingMode</code> is <code>gstExclusive</code> (default) or <code>gstInclusive</code>. JSON <code>null</code> selects each default. One pricing mode applies to every line. <code>rate</code> is the unit price before discount, GST included only for <code>gstInclusive</code>; choose a native item-wise sale/purchase type whose inclusive setting matches. Tax rates come from each selected item's configured category for this company/year; local uses CGST+SGST, central uses IGST. Mixed-rate lines are allowed. Auto computes money using decimal arithmetic. Manual requires every line's <code>amounts</code> and document <code>totals</code>, each with <code>taxableAmount</code>, <code>cgst</code>, <code>sgst</code>, <code>igst</code>, <code>amount</code> (JSON numbers, max two decimals). <code>amount</code> equals taxable plus components; totals equal exact line sums. Local IGST and central CGST/SGST must be zero; submitted values must satisfy the narrow configured-rate and one-paisa bounds in <code>docs/features/BUSY-GST-Billing-Modes-Create-API.md</code>. No balancing charge or silent replacement. Returns submit positive amounts; BUSY posts reversal signs. Malformed JSON or unknown fields: <code>400 BAD_REQUEST</code>; missing or inconsistent Manual amounts: <code>400 INVALID_PARAMETER</code>; invalid configured-rate/treatment: <code>422 GST_AMOUNTS_INVALID</code>; unproven new-mode combination: <code>422 GST_MODE_UNSUPPORTED</code>; changed configuration before save: <code>409 GST_CONFIGURATION_CHANGED</code>. If saved read-back mismatches: <code>502 BUSY_WRITE_UNVERIFIED</code> means saved and requires reconciliation, never automatic retry. Linked returns and bill allocations, manual Purchase sundry discounts, and zero/exempt/nil treatment are not proven for new modes; existing Auto/exclusive supported flows remain. Cloud routes are not claimed deployed.</p>\n<p><strong>Native E-Invoice Required flag:</strong> Optional nullable boolean <code>eInvoiceRequired</code>; <code>true</code> persists Yes and <code>false</code> persists No. Omit or send <code>null</code> for prior creation behaviour. It does not change E-Way Bill Required, generate an IRN, contact GST services or prove Bulk E-Invoice eligibility. Local source commit <code>d650913</code>; bounded internal-candidate installed flag persistence accepted 2026-10-20 on both providers; 0.0.16 release smoke was narrower.</p>\n<p><strong>Mode payload examples</strong> (fragments; retain the route's company/year/date/reference/party/series/centre fields and use a matching configured native type):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\"taxCalculation\":\"auto\",\"pricingMode\":\"gstExclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 5% item\"},\"quantity\":1.25,\"rate\":10.10}]}\n{\"taxCalculation\":\"auto\",\"pricingMode\":\"gstInclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 18% item\"},\"quantity\":0.5,\"rate\":25.00}]}\n{\"taxCalculation\":\"manual\",\"pricingMode\":\"gstExclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 5% item\"},\"quantity\":1.25,\"rate\":10.10,\"amounts\":{\"taxableAmount\":12.62,\"cgst\":0.32,\"sgst\":0.32,\"igst\":0,\"amount\":13.26}}],\"totals\":{\"taxableAmount\":12.62,\"cgst\":0.32,\"sgst\":0.32,\"igst\":0,\"amount\":13.26}}\n{\"taxCalculation\":\"manual\",\"pricingMode\":\"gstInclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 18% item\"},\"quantity\":0.5,\"rate\":25.00,\"amounts\":{\"taxableAmount\":10.59,\"cgst\":0.96,\"sgst\":0.95,\"igst\":0,\"amount\":12.50}}],\"totals\":{\"taxableAmount\":10.59,\"cgst\":0.96,\"sgst\":0.95,\"igst\":0,\"amount\":12.50}}\n</code></pre>\n<p><strong>Mixed-rate Manual inclusive example:</strong> one 5% line may use a different configured tax category from an 18% line; sum every five amounts members exactly into totals. For central treatment replace both local components with IGST under the selected central native type. The one-paisa 18% example above shows the corrected CGST/SGST mapping. These are synthetic fragments, not live execution records.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n<h2 id=\"full-synthetic-gst-request-examples-local-only\">FULL synthetic GST request examples (Local only)</h2>\n<p>The raw Body tab above stays the minimal Auto/exclusive request. These separate complete bodies assume existing synthetic 5%/18% item tax categories, a matching item-wise native type, series, party and centre in the selected company/FY; replace fixture names and use a fresh reference before any send. <code>Local-TaxIncl.</code> must be configured with inclusive B13. Every line shares the voucher pricing mode. The amounts below are local CGST/SGST examples; for interstate treatment select the matching Central type and supply IGST instead. Return amounts remain positive in the request and BUSY reverses the postings. Do not infer Cloud Relay deployment from these Windows Local examples.</p>\n<p><strong>Auto + inclusive (synthetic FULL body):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstInclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-TaxIncl.\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic GST 18% Item\"\n      },\n      \"quantity\": 0.5,\n      \"rate\": 25\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"eInvoiceRequired\": true\n}\n</code></pre>\n<p><strong>Manual + exclusive (synthetic FULL body):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic GST 5% Item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0,\n        \"amount\": 13.26\n      }\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0,\n    \"amount\": 13.26\n  },\n  \"eInvoiceRequired\": true\n}\n</code></pre>\n<p><strong>Manual + inclusive (synthetic FULL body):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstInclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-TaxIncl.\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic GST 18% Item\"\n      },\n      \"quantity\": 0.5,\n      \"rate\": 25,\n      \"amounts\": {\n        \"taxableAmount\": 10.59,\n        \"cgst\": 0.96,\n        \"sgst\": 0.95,\n        \"igst\": 0,\n        \"amount\": 12.5\n      }\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"totals\": {\n    \"taxableAmount\": 10.59,\n    \"cgst\": 0.96,\n    \"sgst\": 0.95,\n    \"igst\": 0,\n    \"amount\": 12.5\n  },\n  \"eInvoiceRequired\": true\n}\n</code></pre>\n<p>The normal request's test requires 200 for a synchronous success; saved 400/409/422/502/504 examples are separate expected-refusal illustrations and do not constitute a successful create assertion. An explicit queue:true request requires 202 and must be polled for its final result.</p>\n<h2 id=\"optional-salesman-local-source-synthetic-examples\">Optional salesman (Local source; synthetic examples)</h2>\n<p><code>salesman</code> is an optional voucher-header object: <code>{\"code\":9701}</code> or <code>{\"name\":\"Synthetic Salesman\"}</code>, exactly one key. It resolves an existing active MasterType-19 Salesman in the selected company/FY, distinct from an account with the same name. BUSY must have effective voucher-level salesman reporting enabled for the selected series. The chosen identity tags the header and every item line; it does not calculate or post commission. Replace synthetic identity and voucher fixtures before any guarded send.</p>\n<p>Omit <code>salesman</code> or send <code>null</code> to retain native default behavior and the existing response shape. A verified explicit assignment adds <code>data.salesman:{code,name}</code> last in a synchronous 200 result or a completed queued result. HTTP 202 only accepts a durable job; inspect its final result before claiming BUSY persistence. The existing 200 example omits salesman; separate saved synthetic examples show assignment and explicit null.</p>\n<p>Exact pre-save refusals: <code>409 SALESMAN_CONFIGURATION_UNSUPPORTED</code> (effective setting), <code>409 SALESMAN_CONFIGURATION_CHANGED</code> (selected identity or frozen configuration changed), and <code>409 BUSY_SETTINGS_UNREADABLE</code> (requested settings unreadable), each with <code>metadata.error.field:\"salesman\"</code>. Unknown or wrong-master-type code/name is <code>422 MASTER_REFERENCE_NOT_FOUND</code>; a duplicate ambiguous name is <code>422 MASTER_REFERENCE_AMBIGUOUS</code>; inactive/unverifiable status is <code>400 INVALID_PARAMETER</code>. Invalid object shape/unknown keys are refused by strict JSON and reference validation. A refusal is not a successful create. Existing <code>502 BUSY_WRITE_UNVERIFIED</code> means a voucher was saved but independent proof differs (including possible salesman fields); <code>504 BUSY_WRITE_UNCERTAIN</code> may have saved. Preserve any known ID, reconcile BUSY and the write job before a new attempt. Never blind-retry or use a fresh reference to mask uncertainty. These examples are source-backed and synthetic, not installed-service or cloud acceptance.</p>\n<p>BUSY write admission: the business invoiceReference, company and FY own the durable Sales Invoice reference. 409 BUSY_WRITE_REFERENCE_IN_PROGRESS means an active prior writer owns it; 409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED means reconcile the original write read-only before any new submission; 503 BUSY_WRITE_ADMISSION_UNAVAILABLE means admission was not confirmed. Preserve the original reference and any known job/voucher ID. 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Installed public v0.0.30 predates this merged source; these are documentation examples only. Do not Send until a newer candidate with this source is installed and the target BUSY series is verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 2,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Postman test line\"\n      ]\n    },\n    {\n      \"item\": {\n        \"name\": \"Parle G\"\n      },\n      \"quantity\": 2.5,\n      \"rate\": 20.1\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 2,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Postman test line\"\n      ]\n    },\n    {\n      \"item\": {\n        \"name\": \"Parle G\"\n      },\n      \"quantity\": 2.5,\n      \"rate\": 20.1\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","sales-invoice-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"dc40dacc-4855-e9f2-0832-61a30332c35e","name":"200 – invoice created (local GST, billing from the customer, no round-off)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 2, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Postman test line\"] },\n    { \"item\": { \"name\": \"Parle G\" }, \"quantity\": 2.5, \"rate\": 20.10 }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-invoice-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `invoiceReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · operation `busy.sales-invoices.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). Before the save AI Zeny reads BUSY's settings: the series must keep separate billing details (`422 BUSY_SETTING_REQUIRED`, field `voucherSeries`), a bill-by-bill customer without `dueDate` needs \"Auto Create Party References in Sales Voucher\" (field `dueDate`), and the series must number automatically (`422 SALES_INVOICE_SERIES_UNSUPPORTED`); `502 BUSY_SETTINGS_UNREADABLE` when BUSY's configuration cannot be read.\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.sales-invoices.create` (`POST /api/v1/sales-invoice-create`) creates one BUSY sales invoice through BUSY's own COM component on this PC. **Create only**: it never changes, cancels or deletes an invoice, never converts a sales order, and never generates an e-invoice or e-way bill. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** installed service-account acceptance passed on 2026-10-14 (COMP0002 / 2026). **Through the cloud: not available** — Windows relays it with the write rules (same organization token), but the AI Zeny cloud has no `/v1/sales-invoice-create` route yet (`404`, 2026-10-14), so there is no Cloud Relay request for it; see `docs/integration/Cloud-Sales-Invoice-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the invoice from the series and derives the ledger lines (customer, sales account, CGST/SGST or IGST accounts) and the customer's bill reference (due on the date plus the customer's credit days). Your `invoiceReference` (1-60) is stored in the first narration and must be unique among the company's sales invoices of the year; `narration` goes to the second narration. AI Zeny calculates each line's amount and GST from the item's tax category (exact decimals, half away from zero, **no round-off**), fills the billing details from the customer and the MRP from the item as BUSY's window does, and compares BUSY's read-back and the saved rows with what was sent before answering.\n\n**Masters are never created.** BUSY's import would create a master for an unknown name, so every customer, item, unit, series, sale type and godown must already exist (`422 MASTER_REFERENCE_NOT_FOUND`) and is checked again with BUSY's own lookup just before the save (`409 SALES_INVOICE_MASTER_CHANGED`).\n\n**Serial-number, batch and parameter items are refused** (`422 SALES_INVOICE_ITEM_UNSUPPORTED`, the message names which): AI Zeny reads the item's own settings in BUSY (serial-number type, batch type, parameter-wise stock), so an item set up for tracking is refused even before any details were recorded, and also refuses an item that already has serial-number or parameter records. BUSY's own import would save such an invoice without the details. Stock below zero and a customer past its credit limit are **not** refused (BUSY's own behaviour).\n\n**Optional:** `dueDate` (`YYYY-MM-DD`; the bill reference is then named by `invoiceReference`, ≤ 25 characters, bill-by-bill customers only), `billing` {`name`, `address1`-`address4`, `mobile`, `email`} (GSTIN, PAN and state stay the customer's), `lines[].mrp`, `lines[].description` (1-10 positions × 1-40, see below), `narration` (1-94), `transport`, `grNumber`, `vehicleNumber`, `station` (1-30), `voucherSeries` (when the company has more than one). Amounts, tax, totals, invoice numbers, ledger lines, XML and any `tmp…` member are refused. Body up to 128 KiB.\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `salesInvoiceReference` (current value) before each send — for example `AZPM-SI-0NN`. The request is skipped without one. Do not reuse `AZPOC-SI-…` or `AZSVC-SI-…` (earlier test records).\n- Nothing is deleted automatically: a created test invoice stays in BUSY.\n- **Never retry blindly.** Sending the same `salesInvoiceReference` again is refused (`409 SALES_INVOICE_REFERENCE_TAKEN`, `details.invoiceId`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `invoiceId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back differs (`details.invoiceId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs, orders and master writes), up to 2 minutes: give the request a long timeout.\n\n**Sets:** `salesInvoiceId` on success (usable as `voucherId` in the Sales invoice PDF request). Public guide: `docs/public/api/sales-invoice-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. Public guide: `docs/public/api/line-descriptions.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"0d9f3a1c5b7e4f2a8c6d1e0b9a8f7e6d"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"invoiceId\": 8802,\n    \"invoiceNumber\": \"21/2026-27\",\n    \"invoiceReference\": \"WEB-INV-20481\",\n    \"date\": \"2026-10-14\",\n    \"voucherSeries\": { \"code\": 258, \"name\": \"Main\" },\n    \"customer\": { \"code\": 7001, \"name\": \"Synthetic Traders\" },\n    \"saleType\": { \"code\": 1223, \"name\": \"Local-ItemWise\" },\n    \"taxation\": \"local\",\n    \"materialCenter\": { \"code\": 201, \"name\": \"Main Store\" },\n    \"lines\": [\n      { \"lineNumber\": 1, \"item\": { \"code\": 9401, \"name\": \"Synthetic Item\" }, \"unit\": \"Pcs.\", \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10, \"netRate\": 135, \"taxableAmount\": 405, \"cgst\": 24.3, \"sgst\": 24.3, \"igst\": 0, \"taxAmount\": 48.6, \"amount\": 453.6, \"mrp\": 210, \"description\": [\"Synthetic description\"] },\n      { \"lineNumber\": 2, \"item\": { \"code\": 9402, \"name\": \"Synthetic Biscuits\" }, \"unit\": \"Pcs.\", \"quantity\": 2.5, \"rate\": 20.1, \"discountPercent\": 0, \"netRate\": 20.1, \"taxableAmount\": 50.25, \"cgst\": 4.52, \"sgst\": 4.52, \"igst\": 0, \"taxAmount\": 9.04, \"amount\": 59.29, \"mrp\": null, \"description\": [] }\n    ],\n    \"totals\": { \"quantity\": 5.5, \"taxableAmount\": 455.25, \"cgst\": 28.82, \"sgst\": 28.82, \"igst\": 0, \"taxAmount\": 57.64, \"amount\": 512.89 },\n    \"ledger\": [\n      { \"account\": { \"code\": 7001, \"name\": \"Synthetic Traders\" }, \"debit\": 512.89, \"credit\": 0 },\n      { \"account\": { \"code\": 4, \"name\": \"Sales\" }, \"debit\": 0, \"credit\": 455.25 },\n      { \"account\": { \"code\": 1142, \"name\": \"CGST Output\" }, \"debit\": 0, \"credit\": 28.82 },\n      { \"account\": { \"code\": 1141, \"name\": \"SGST Output\" }, \"debit\": 0, \"credit\": 28.82 }\n    ],\n    \"billReference\": { \"number\": \"21/2026-27\", \"dueDate\": \"2026-10-29\", \"amount\": 512.89, \"dueDateSource\": \"creditDays\" },\n    \"billing\": { \"source\": \"customer\", \"name\": \"Synthetic Traders\", \"address1\": \"1 Example Road\", \"address2\": \"Example Town\", \"address3\": null, \"address4\": null, \"mobile\": \"9000000001\", \"email\": null, \"gstNumber\": null, \"panNumber\": null, \"state\": \"Madhya Pradesh\" },\n    \"otherDetails\": { \"narration\": \"Synthetic order from the web shop\", \"transport\": \"Synthetic Transport Co\", \"grNumber\": null, \"vehicleNumber\": \"XX00ZZ0000\", \"station\": null }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-invoices.create\",\n    \"requestId\": \"0d9f3a1c5b7e4f2a8c6d1e0b9a8f7e6d\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 2,\n    \"verification\": [\"busyReadBack\", \"savedRows\"],\n    \"elapsedMs\": 6240,\n    \"executedAt\": \"2026-10-14T06:30:00+00:00\"\n  }\n}"},{"id":"028082c2-d449-36eb-68c8-6ec5120aa668","name":"409 – reference already held (safe retry)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 2, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Postman test line\"] },\n    { \"item\": { \"name\": \"Parle G\" }, \"quantity\": 2.5, \"rate\": 20.10 }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-invoice-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `invoiceReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · operation `busy.sales-invoices.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). Before the save AI Zeny reads BUSY's settings: the series must keep separate billing details (`422 BUSY_SETTING_REQUIRED`, field `voucherSeries`), a bill-by-bill customer without `dueDate` needs \"Auto Create Party References in Sales Voucher\" (field `dueDate`), and the series must number automatically (`422 SALES_INVOICE_SERIES_UNSUPPORTED`); `502 BUSY_SETTINGS_UNREADABLE` when BUSY's configuration cannot be read.\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.sales-invoices.create` (`POST /api/v1/sales-invoice-create`) creates one BUSY sales invoice through BUSY's own COM component on this PC. **Create only**: it never changes, cancels or deletes an invoice, never converts a sales order, and never generates an e-invoice or e-way bill. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** installed service-account acceptance passed on 2026-10-14 (COMP0002 / 2026). **Through the cloud: not available** — Windows relays it with the write rules (same organization token), but the AI Zeny cloud has no `/v1/sales-invoice-create` route yet (`404`, 2026-10-14), so there is no Cloud Relay request for it; see `docs/integration/Cloud-Sales-Invoice-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the invoice from the series and derives the ledger lines (customer, sales account, CGST/SGST or IGST accounts) and the customer's bill reference (due on the date plus the customer's credit days). Your `invoiceReference` (1-60) is stored in the first narration and must be unique among the company's sales invoices of the year; `narration` goes to the second narration. AI Zeny calculates each line's amount and GST from the item's tax category (exact decimals, half away from zero, **no round-off**), fills the billing details from the customer and the MRP from the item as BUSY's window does, and compares BUSY's read-back and the saved rows with what was sent before answering.\n\n**Masters are never created.** BUSY's import would create a master for an unknown name, so every customer, item, unit, series, sale type and godown must already exist (`422 MASTER_REFERENCE_NOT_FOUND`) and is checked again with BUSY's own lookup just before the save (`409 SALES_INVOICE_MASTER_CHANGED`).\n\n**Serial-number, batch and parameter items are refused** (`422 SALES_INVOICE_ITEM_UNSUPPORTED`, the message names which): AI Zeny reads the item's own settings in BUSY (serial-number type, batch type, parameter-wise stock), so an item set up for tracking is refused even before any details were recorded, and also refuses an item that already has serial-number or parameter records. BUSY's own import would save such an invoice without the details. Stock below zero and a customer past its credit limit are **not** refused (BUSY's own behaviour).\n\n**Optional:** `dueDate` (`YYYY-MM-DD`; the bill reference is then named by `invoiceReference`, ≤ 25 characters, bill-by-bill customers only), `billing` {`name`, `address1`-`address4`, `mobile`, `email`} (GSTIN, PAN and state stay the customer's), `lines[].mrp`, `lines[].description` (1-10 positions × 1-40, see below), `narration` (1-94), `transport`, `grNumber`, `vehicleNumber`, `station` (1-30), `voucherSeries` (when the company has more than one). Amounts, tax, totals, invoice numbers, ledger lines, XML and any `tmp…` member are refused. Body up to 128 KiB.\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `salesInvoiceReference` (current value) before each send — for example `AZPM-SI-0NN`. The request is skipped without one. Do not reuse `AZPOC-SI-…` or `AZSVC-SI-…` (earlier test records).\n- Nothing is deleted automatically: a created test invoice stays in BUSY.\n- **Never retry blindly.** Sending the same `salesInvoiceReference` again is refused (`409 SALES_INVOICE_REFERENCE_TAKEN`, `details.invoiceId`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `invoiceId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back differs (`details.invoiceId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs, orders and master writes), up to 2 minutes: give the request a long timeout.\n\n**Sets:** `salesInvoiceId` on success (usable as `voucherId` in the Sales invoice PDF request). Public guide: `docs/public/api/sales-invoice-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. Public guide: `docs/public/api/line-descriptions.md`."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"requestId\": \"7a1b2c3d4e5f60718293a4b5c6d7e8f9\",\n    \"error\": {\n      \"code\": \"SALES_INVOICE_REFERENCE_TAKEN\",\n      \"message\": \"A sales invoice of this company and financial year already holds this invoiceReference. A create never changes an existing invoice; if your earlier call saved it, metadata.error.details.invoiceId names it.\",\n      \"field\": \"invoiceReference\",\n      \"details\": { \"invoiceId\": 8802 }\n    }\n  }\n}"},{"id":"91f125fc-6882-44ef-e7b6-9b71558b9cf0","name":"422 – unknown item refused before BUSY (no master is created)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 2, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Postman test line\"] },\n    { \"item\": { \"name\": \"Parle G\" }, \"quantity\": 2.5, \"rate\": 20.10 }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-invoice-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `invoiceReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · operation `busy.sales-invoices.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). Before the save AI Zeny reads BUSY's settings: the series must keep separate billing details (`422 BUSY_SETTING_REQUIRED`, field `voucherSeries`), a bill-by-bill customer without `dueDate` needs \"Auto Create Party References in Sales Voucher\" (field `dueDate`), and the series must number automatically (`422 SALES_INVOICE_SERIES_UNSUPPORTED`); `502 BUSY_SETTINGS_UNREADABLE` when BUSY's configuration cannot be read.\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.sales-invoices.create` (`POST /api/v1/sales-invoice-create`) creates one BUSY sales invoice through BUSY's own COM component on this PC. **Create only**: it never changes, cancels or deletes an invoice, never converts a sales order, and never generates an e-invoice or e-way bill. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** installed service-account acceptance passed on 2026-10-14 (COMP0002 / 2026). **Through the cloud: not available** — Windows relays it with the write rules (same organization token), but the AI Zeny cloud has no `/v1/sales-invoice-create` route yet (`404`, 2026-10-14), so there is no Cloud Relay request for it; see `docs/integration/Cloud-Sales-Invoice-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the invoice from the series and derives the ledger lines (customer, sales account, CGST/SGST or IGST accounts) and the customer's bill reference (due on the date plus the customer's credit days). Your `invoiceReference` (1-60) is stored in the first narration and must be unique among the company's sales invoices of the year; `narration` goes to the second narration. AI Zeny calculates each line's amount and GST from the item's tax category (exact decimals, half away from zero, **no round-off**), fills the billing details from the customer and the MRP from the item as BUSY's window does, and compares BUSY's read-back and the saved rows with what was sent before answering.\n\n**Masters are never created.** BUSY's import would create a master for an unknown name, so every customer, item, unit, series, sale type and godown must already exist (`422 MASTER_REFERENCE_NOT_FOUND`) and is checked again with BUSY's own lookup just before the save (`409 SALES_INVOICE_MASTER_CHANGED`).\n\n**Serial-number, batch and parameter items are refused** (`422 SALES_INVOICE_ITEM_UNSUPPORTED`, the message names which): AI Zeny reads the item's own settings in BUSY (serial-number type, batch type, parameter-wise stock), so an item set up for tracking is refused even before any details were recorded, and also refuses an item that already has serial-number or parameter records. BUSY's own import would save such an invoice without the details. Stock below zero and a customer past its credit limit are **not** refused (BUSY's own behaviour).\n\n**Optional:** `dueDate` (`YYYY-MM-DD`; the bill reference is then named by `invoiceReference`, ≤ 25 characters, bill-by-bill customers only), `billing` {`name`, `address1`-`address4`, `mobile`, `email`} (GSTIN, PAN and state stay the customer's), `lines[].mrp`, `lines[].description` (1-10 positions × 1-40, see below), `narration` (1-94), `transport`, `grNumber`, `vehicleNumber`, `station` (1-30), `voucherSeries` (when the company has more than one). Amounts, tax, totals, invoice numbers, ledger lines, XML and any `tmp…` member are refused. Body up to 128 KiB.\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `salesInvoiceReference` (current value) before each send — for example `AZPM-SI-0NN`. The request is skipped without one. Do not reuse `AZPOC-SI-…` or `AZSVC-SI-…` (earlier test records).\n- Nothing is deleted automatically: a created test invoice stays in BUSY.\n- **Never retry blindly.** Sending the same `salesInvoiceReference` again is refused (`409 SALES_INVOICE_REFERENCE_TAKEN`, `details.invoiceId`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `invoiceId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back differs (`details.invoiceId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs, orders and master writes), up to 2 minutes: give the request a long timeout.\n\n**Sets:** `salesInvoiceId` on success (usable as `voucherId` in the Sales invoice PDF request). Public guide: `docs/public/api/sales-invoice-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. Public guide: `docs/public/api/line-descriptions.md`."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"requestId\": \"1f2e3d4c5b6a79881726354453627180\",\n    \"error\": {\n      \"code\": \"MASTER_REFERENCE_NOT_FOUND\",\n      \"message\": \"No item with that code or name exists in this company and financial year.\",\n      \"field\": \"lines[1].item\"\n    }\n  }\n}"},{"id":"0ed19d3e-f93d-838c-195e-4b81b676a0ac","name":"504 – uncertain, reconciled (found): do not resend with a new reference","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 2, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Postman test line\"] },\n    { \"item\": { \"name\": \"Parle G\" }, \"quantity\": 2.5, \"rate\": 20.10 }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-invoice-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `invoiceReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · operation `busy.sales-invoices.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). Before the save AI Zeny reads BUSY's settings: the series must keep separate billing details (`422 BUSY_SETTING_REQUIRED`, field `voucherSeries`), a bill-by-bill customer without `dueDate` needs \"Auto Create Party References in Sales Voucher\" (field `dueDate`), and the series must number automatically (`422 SALES_INVOICE_SERIES_UNSUPPORTED`); `502 BUSY_SETTINGS_UNREADABLE` when BUSY's configuration cannot be read.\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.sales-invoices.create` (`POST /api/v1/sales-invoice-create`) creates one BUSY sales invoice through BUSY's own COM component on this PC. **Create only**: it never changes, cancels or deletes an invoice, never converts a sales order, and never generates an e-invoice or e-way bill. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** installed service-account acceptance passed on 2026-10-14 (COMP0002 / 2026). **Through the cloud: not available** — Windows relays it with the write rules (same organization token), but the AI Zeny cloud has no `/v1/sales-invoice-create` route yet (`404`, 2026-10-14), so there is no Cloud Relay request for it; see `docs/integration/Cloud-Sales-Invoice-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the invoice from the series and derives the ledger lines (customer, sales account, CGST/SGST or IGST accounts) and the customer's bill reference (due on the date plus the customer's credit days). Your `invoiceReference` (1-60) is stored in the first narration and must be unique among the company's sales invoices of the year; `narration` goes to the second narration. AI Zeny calculates each line's amount and GST from the item's tax category (exact decimals, half away from zero, **no round-off**), fills the billing details from the customer and the MRP from the item as BUSY's window does, and compares BUSY's read-back and the saved rows with what was sent before answering.\n\n**Masters are never created.** BUSY's import would create a master for an unknown name, so every customer, item, unit, series, sale type and godown must already exist (`422 MASTER_REFERENCE_NOT_FOUND`) and is checked again with BUSY's own lookup just before the save (`409 SALES_INVOICE_MASTER_CHANGED`).\n\n**Serial-number, batch and parameter items are refused** (`422 SALES_INVOICE_ITEM_UNSUPPORTED`, the message names which): AI Zeny reads the item's own settings in BUSY (serial-number type, batch type, parameter-wise stock), so an item set up for tracking is refused even before any details were recorded, and also refuses an item that already has serial-number or parameter records. BUSY's own import would save such an invoice without the details. Stock below zero and a customer past its credit limit are **not** refused (BUSY's own behaviour).\n\n**Optional:** `dueDate` (`YYYY-MM-DD`; the bill reference is then named by `invoiceReference`, ≤ 25 characters, bill-by-bill customers only), `billing` {`name`, `address1`-`address4`, `mobile`, `email`} (GSTIN, PAN and state stay the customer's), `lines[].mrp`, `lines[].description` (1-10 positions × 1-40, see below), `narration` (1-94), `transport`, `grNumber`, `vehicleNumber`, `station` (1-30), `voucherSeries` (when the company has more than one). Amounts, tax, totals, invoice numbers, ledger lines, XML and any `tmp…` member are refused. Body up to 128 KiB.\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `salesInvoiceReference` (current value) before each send — for example `AZPM-SI-0NN`. The request is skipped without one. Do not reuse `AZPOC-SI-…` or `AZSVC-SI-…` (earlier test records).\n- Nothing is deleted automatically: a created test invoice stays in BUSY.\n- **Never retry blindly.** Sending the same `salesInvoiceReference` again is refused (`409 SALES_INVOICE_REFERENCE_TAKEN`, `details.invoiceId`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `invoiceId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back differs (`details.invoiceId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs, orders and master writes), up to 2 minutes: give the request a long timeout.\n\n**Sets:** `salesInvoiceId` on success (usable as `voucherId` in the Sales invoice PDF request). Public guide: `docs/public/api/sales-invoice-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. Public guide: `docs/public/api/line-descriptions.md`."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"requestId\": \"9e8d7c6b5a4938271605f4e3d2c1b0a9\",\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"BUSY stopped while saving the sales invoice; a sales invoice with this invoiceReference exists now (metadata.error.details.invoiceId). Check it in BUSY; do not send it again.\",\n      \"details\": { \"invoiceId\": 8802, \"reconciliation\": \"found\" }\n    }\n  }\n}"},{"id":"67201164-0fe9-e3e3-25d9-2677c8600f26","name":"200 – illustrative E-Invoice Required Yes request (Local only)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 2,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Postman test line\"\n      ]\n    },\n    {\n      \"item\": {\n        \"name\": \"Parle G\"\n      },\n      \"quantity\": 2.5,\n      \"rate\": 20.1\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"eInvoiceRequired\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"invoiceId\": 8802,\n    \"invoiceNumber\": \"21/2026-27\",\n    \"invoiceReference\": \"WEB-INV-20481\",\n    \"date\": \"2026-10-14\",\n    \"voucherSeries\": { \"code\": 258, \"name\": \"Main\" },\n    \"customer\": { \"code\": 7001, \"name\": \"Synthetic Traders\" },\n    \"saleType\": { \"code\": 1223, \"name\": \"Local-ItemWise\" },\n    \"taxation\": \"local\",\n    \"materialCenter\": { \"code\": 201, \"name\": \"Main Store\" },\n    \"lines\": [\n      { \"lineNumber\": 1, \"item\": { \"code\": 9401, \"name\": \"Synthetic Item\" }, \"unit\": \"Pcs.\", \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10, \"netRate\": 135, \"taxableAmount\": 405, \"cgst\": 24.3, \"sgst\": 24.3, \"igst\": 0, \"taxAmount\": 48.6, \"amount\": 453.6, \"mrp\": 210, \"description\": [\"Synthetic description\"] },\n      { \"lineNumber\": 2, \"item\": { \"code\": 9402, \"name\": \"Synthetic Biscuits\" }, \"unit\": \"Pcs.\", \"quantity\": 2.5, \"rate\": 20.1, \"discountPercent\": 0, \"netRate\": 20.1, \"taxableAmount\": 50.25, \"cgst\": 4.52, \"sgst\": 4.52, \"igst\": 0, \"taxAmount\": 9.04, \"amount\": 59.29, \"mrp\": null, \"description\": [] }\n    ],\n    \"totals\": { \"quantity\": 5.5, \"taxableAmount\": 455.25, \"cgst\": 28.82, \"sgst\": 28.82, \"igst\": 0, \"taxAmount\": 57.64, \"amount\": 512.89 },\n    \"ledger\": [\n      { \"account\": { \"code\": 7001, \"name\": \"Synthetic Traders\" }, \"debit\": 512.89, \"credit\": 0 },\n      { \"account\": { \"code\": 4, \"name\": \"Sales\" }, \"debit\": 0, \"credit\": 455.25 },\n      { \"account\": { \"code\": 1142, \"name\": \"CGST Output\" }, \"debit\": 0, \"credit\": 28.82 },\n      { \"account\": { \"code\": 1141, \"name\": \"SGST Output\" }, \"debit\": 0, \"credit\": 28.82 }\n    ],\n    \"billReference\": { \"number\": \"21/2026-27\", \"dueDate\": \"2026-10-29\", \"amount\": 512.89, \"dueDateSource\": \"creditDays\" },\n    \"billing\": { \"source\": \"customer\", \"name\": \"Synthetic Traders\", \"address1\": \"1 Example Road\", \"address2\": \"Example Town\", \"address3\": null, \"address4\": null, \"mobile\": \"9000000001\", \"email\": null, \"gstNumber\": null, \"panNumber\": null, \"state\": \"Madhya Pradesh\" },\n    \"otherDetails\": { \"narration\": \"Synthetic order from the web shop\", \"transport\": \"Synthetic Transport Co\", \"grNumber\": null, \"vehicleNumber\": \"XX00ZZ0000\", \"station\": null }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-invoices.create\",\n    \"requestId\": \"0d9f3a1c5b7e4f2a8c6d1e0b9a8f7e6d\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 2,\n    \"verification\": [\"busyReadBack\", \"savedRows\"],\n    \"elapsedMs\": 6240,\n    \"executedAt\": \"2026-10-14T06:30:00+00:00\"\n  }\n}"},{"id":"a3e6317d-ac09-2139-163c-b9e23e92dbb9","name":"200 – illustrative E-Invoice Required No request (Local only)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 2,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Postman test line\"\n      ]\n    },\n    {\n      \"item\": {\n        \"name\": \"Parle G\"\n      },\n      \"quantity\": 2.5,\n      \"rate\": 20.1\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"eInvoiceRequired\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"invoiceId\": 8802,\n    \"invoiceNumber\": \"21/2026-27\",\n    \"invoiceReference\": \"WEB-INV-20481\",\n    \"date\": \"2026-10-14\",\n    \"voucherSeries\": { \"code\": 258, \"name\": \"Main\" },\n    \"customer\": { \"code\": 7001, \"name\": \"Synthetic Traders\" },\n    \"saleType\": { \"code\": 1223, \"name\": \"Local-ItemWise\" },\n    \"taxation\": \"local\",\n    \"materialCenter\": { \"code\": 201, \"name\": \"Main Store\" },\n    \"lines\": [\n      { \"lineNumber\": 1, \"item\": { \"code\": 9401, \"name\": \"Synthetic Item\" }, \"unit\": \"Pcs.\", \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10, \"netRate\": 135, \"taxableAmount\": 405, \"cgst\": 24.3, \"sgst\": 24.3, \"igst\": 0, \"taxAmount\": 48.6, \"amount\": 453.6, \"mrp\": 210, \"description\": [\"Synthetic description\"] },\n      { \"lineNumber\": 2, \"item\": { \"code\": 9402, \"name\": \"Synthetic Biscuits\" }, \"unit\": \"Pcs.\", \"quantity\": 2.5, \"rate\": 20.1, \"discountPercent\": 0, \"netRate\": 20.1, \"taxableAmount\": 50.25, \"cgst\": 4.52, \"sgst\": 4.52, \"igst\": 0, \"taxAmount\": 9.04, \"amount\": 59.29, \"mrp\": null, \"description\": [] }\n    ],\n    \"totals\": { \"quantity\": 5.5, \"taxableAmount\": 455.25, \"cgst\": 28.82, \"sgst\": 28.82, \"igst\": 0, \"taxAmount\": 57.64, \"amount\": 512.89 },\n    \"ledger\": [\n      { \"account\": { \"code\": 7001, \"name\": \"Synthetic Traders\" }, \"debit\": 512.89, \"credit\": 0 },\n      { \"account\": { \"code\": 4, \"name\": \"Sales\" }, \"debit\": 0, \"credit\": 455.25 },\n      { \"account\": { \"code\": 1142, \"name\": \"CGST Output\" }, \"debit\": 0, \"credit\": 28.82 },\n      { \"account\": { \"code\": 1141, \"name\": \"SGST Output\" }, \"debit\": 0, \"credit\": 28.82 }\n    ],\n    \"billReference\": { \"number\": \"21/2026-27\", \"dueDate\": \"2026-10-29\", \"amount\": 512.89, \"dueDateSource\": \"creditDays\" },\n    \"billing\": { \"source\": \"customer\", \"name\": \"Synthetic Traders\", \"address1\": \"1 Example Road\", \"address2\": \"Example Town\", \"address3\": null, \"address4\": null, \"mobile\": \"9000000001\", \"email\": null, \"gstNumber\": null, \"panNumber\": null, \"state\": \"Madhya Pradesh\" },\n    \"otherDetails\": { \"narration\": \"Synthetic order from the web shop\", \"transport\": \"Synthetic Transport Co\", \"grNumber\": null, \"vehicleNumber\": \"XX00ZZ0000\", \"station\": null }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-invoices.create\",\n    \"requestId\": \"0d9f3a1c5b7e4f2a8c6d1e0b9a8f7e6d\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 2,\n    \"verification\": [\"busyReadBack\", \"savedRows\"],\n    \"elapsedMs\": 6240,\n    \"executedAt\": \"2026-10-14T06:30:00+00:00\"\n  }\n}"},{"id":"2692d591-d276-afbf-61b2-9e6def79eafe","name":"200 – illustrative E-Invoice Required omitted request (Local only)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 2,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Postman test line\"\n      ]\n    },\n    {\n      \"item\": {\n        \"name\": \"Parle G\"\n      },\n      \"quantity\": 2.5,\n      \"rate\": 20.1\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"invoiceId\": 8802,\n    \"invoiceNumber\": \"21/2026-27\",\n    \"invoiceReference\": \"WEB-INV-20481\",\n    \"date\": \"2026-10-14\",\n    \"voucherSeries\": { \"code\": 258, \"name\": \"Main\" },\n    \"customer\": { \"code\": 7001, \"name\": \"Synthetic Traders\" },\n    \"saleType\": { \"code\": 1223, \"name\": \"Local-ItemWise\" },\n    \"taxation\": \"local\",\n    \"materialCenter\": { \"code\": 201, \"name\": \"Main Store\" },\n    \"lines\": [\n      { \"lineNumber\": 1, \"item\": { \"code\": 9401, \"name\": \"Synthetic Item\" }, \"unit\": \"Pcs.\", \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10, \"netRate\": 135, \"taxableAmount\": 405, \"cgst\": 24.3, \"sgst\": 24.3, \"igst\": 0, \"taxAmount\": 48.6, \"amount\": 453.6, \"mrp\": 210, \"description\": [\"Synthetic description\"] },\n      { \"lineNumber\": 2, \"item\": { \"code\": 9402, \"name\": \"Synthetic Biscuits\" }, \"unit\": \"Pcs.\", \"quantity\": 2.5, \"rate\": 20.1, \"discountPercent\": 0, \"netRate\": 20.1, \"taxableAmount\": 50.25, \"cgst\": 4.52, \"sgst\": 4.52, \"igst\": 0, \"taxAmount\": 9.04, \"amount\": 59.29, \"mrp\": null, \"description\": [] }\n    ],\n    \"totals\": { \"quantity\": 5.5, \"taxableAmount\": 455.25, \"cgst\": 28.82, \"sgst\": 28.82, \"igst\": 0, \"taxAmount\": 57.64, \"amount\": 512.89 },\n    \"ledger\": [\n      { \"account\": { \"code\": 7001, \"name\": \"Synthetic Traders\" }, \"debit\": 512.89, \"credit\": 0 },\n      { \"account\": { \"code\": 4, \"name\": \"Sales\" }, \"debit\": 0, \"credit\": 455.25 },\n      { \"account\": { \"code\": 1142, \"name\": \"CGST Output\" }, \"debit\": 0, \"credit\": 28.82 },\n      { \"account\": { \"code\": 1141, \"name\": \"SGST Output\" }, \"debit\": 0, \"credit\": 28.82 }\n    ],\n    \"billReference\": { \"number\": \"21/2026-27\", \"dueDate\": \"2026-10-29\", \"amount\": 512.89, \"dueDateSource\": \"creditDays\" },\n    \"billing\": { \"source\": \"customer\", \"name\": \"Synthetic Traders\", \"address1\": \"1 Example Road\", \"address2\": \"Example Town\", \"address3\": null, \"address4\": null, \"mobile\": \"9000000001\", \"email\": null, \"gstNumber\": null, \"panNumber\": null, \"state\": \"Madhya Pradesh\" },\n    \"otherDetails\": { \"narration\": \"Synthetic order from the web shop\", \"transport\": \"Synthetic Transport Co\", \"grNumber\": null, \"vehicleNumber\": \"XX00ZZ0000\", \"station\": null }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-invoices.create\",\n    \"requestId\": \"0d9f3a1c5b7e4f2a8c6d1e0b9a8f7e6d\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 2,\n    \"verification\": [\"busyReadBack\", \"savedRows\"],\n    \"elapsedMs\": 6240,\n    \"executedAt\": \"2026-10-14T06:30:00+00:00\"\n  }\n}"},{"id":"93c2be72-7f50-3840-88e8-5012a15d419a","name":"409 – GST_CONFIGURATION_CHANGED (before save)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic 5% item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0,\n        \"amount\": 13.26\n      }\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0,\n    \"amount\": 13.26\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"GST_CONFIGURATION_CHANGED\",\n      \"message\": \"BUSY's selected GST or voucher-series configuration changed while this request was being prepared. Read it again and submit a new request.\"\n    }\n  }\n}"},{"id":"d2a9f7ca-2803-db36-038e-bec7d99e2fc5","name":"422 – GST_AMOUNTS_INVALID (manual treatment)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic 5% item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0.05,\n        \"amount\": 13.31\n      }\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0.05,\n    \"amount\": 13.31\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"GST_AMOUNTS_INVALID\",\n      \"message\": \"Manual GST amounts conflict with the selected tax rate or local/central treatment.\"\n    }\n  }\n}"},{"id":"e3598e9e-fe15-5512-578e-99ca5faf9631","name":"502 – BUSY_WRITE_UNVERIFIED (saved; reconcile)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic 5% item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0,\n        \"amount\": 13.26\n      }\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0,\n    \"amount\": 13.26\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNVERIFIED\",\n      \"message\": \"BUSY saved the voucher but read-back differs; inspect the saved reference and do not resend.\"\n    }\n  }\n}"},{"id":"df666e8a-c2b4-da33-4227-bc21b6063710","name":"400 – INVALID_PARAMETER (Manual breakdown missing)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 2,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Postman test line\"\n      ]\n    },\n    {\n      \"item\": {\n        \"name\": \"Parle G\"\n      },\n      \"quantity\": 2.5,\n      \"rate\": 20.1\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"Manual GST breakdown is required for every line and document totals.\"\n    }\n  }\n}"},{"id":"b410e8aa-afdd-b7d5-d25c-c77c633e63aa","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 2,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Postman test line\"\n      ]\n    },\n    {\n      \"item\": {\n        \"name\": \"Parle G\"\n      },\n      \"quantity\": 2.5,\n      \"rate\": 20.1\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"synthetic-queue-001"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-invoices.create\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"},{"id":"7dd2c5db-c93f-6920-0ae4-4845840be713","name":"200 – salesman assigned (synthetic Local; name)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 2,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Postman test line\"\n      ]\n    },\n    {\n      \"item\": {\n        \"name\": \"Parle G\"\n      },\n      \"quantity\": 2.5,\n      \"rate\": 20.1\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"salesman\": {\n    \"name\": \"Synthetic Salesman\"\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"invoiceId\": 8802,\n    \"invoiceNumber\": \"21/2026-27\",\n    \"invoiceReference\": \"WEB-INV-20481\",\n    \"date\": \"2026-10-14\",\n    \"voucherSeries\": {\n      \"code\": 258,\n      \"name\": \"Main\"\n    },\n    \"customer\": {\n      \"code\": 7001,\n      \"name\": \"Synthetic Traders\"\n    },\n    \"saleType\": {\n      \"code\": 1223,\n      \"name\": \"Local-ItemWise\"\n    },\n    \"taxation\": \"local\",\n    \"materialCenter\": {\n      \"code\": 201,\n      \"name\": \"Main Store\"\n    },\n    \"lines\": [\n      {\n        \"lineNumber\": 1,\n        \"item\": {\n          \"code\": 9401,\n          \"name\": \"Synthetic Item\"\n        },\n        \"unit\": \"Pcs.\",\n        \"quantity\": 3,\n        \"rate\": 150,\n        \"discountPercent\": 10,\n        \"netRate\": 135,\n        \"taxableAmount\": 405,\n        \"cgst\": 24.3,\n        \"sgst\": 24.3,\n        \"igst\": 0,\n        \"taxAmount\": 48.6,\n        \"amount\": 453.6,\n        \"mrp\": 210,\n        \"description\": [\n          \"Synthetic description\"\n        ]\n      },\n      {\n        \"lineNumber\": 2,\n        \"item\": {\n          \"code\": 9402,\n          \"name\": \"Synthetic Biscuits\"\n        },\n        \"unit\": \"Pcs.\",\n        \"quantity\": 2.5,\n        \"rate\": 20.1,\n        \"discountPercent\": 0,\n        \"netRate\": 20.1,\n        \"taxableAmount\": 50.25,\n        \"cgst\": 4.52,\n        \"sgst\": 4.52,\n        \"igst\": 0,\n        \"taxAmount\": 9.04,\n        \"amount\": 59.29,\n        \"mrp\": null,\n        \"description\": []\n      }\n    ],\n    \"totals\": {\n      \"quantity\": 5.5,\n      \"taxableAmount\": 455.25,\n      \"cgst\": 28.82,\n      \"sgst\": 28.82,\n      \"igst\": 0,\n      \"taxAmount\": 57.64,\n      \"amount\": 512.89\n    },\n    \"ledger\": [\n      {\n        \"account\": {\n          \"code\": 7001,\n          \"name\": \"Synthetic Traders\"\n        },\n        \"debit\": 512.89,\n        \"credit\": 0\n      },\n      {\n        \"account\": {\n          \"code\": 4,\n          \"name\": \"Sales\"\n        },\n        \"debit\": 0,\n        \"credit\": 455.25\n      },\n      {\n        \"account\": {\n          \"code\": 1142,\n          \"name\": \"CGST Output\"\n        },\n        \"debit\": 0,\n        \"credit\": 28.82\n      },\n      {\n        \"account\": {\n          \"code\": 1141,\n          \"name\": \"SGST Output\"\n        },\n        \"debit\": 0,\n        \"credit\": 28.82\n      }\n    ],\n    \"billReference\": {\n      \"number\": \"21/2026-27\",\n      \"dueDate\": \"2026-10-29\",\n      \"amount\": 512.89,\n      \"dueDateSource\": \"creditDays\"\n    },\n    \"billing\": {\n      \"source\": \"customer\",\n      \"name\": \"Synthetic Traders\",\n      \"address1\": \"1 Example Road\",\n      \"address2\": \"Example Town\",\n      \"address3\": null,\n      \"address4\": null,\n      \"mobile\": \"9000000001\",\n      \"email\": null,\n      \"gstNumber\": null,\n      \"panNumber\": null,\n      \"state\": \"Madhya Pradesh\"\n    },\n    \"otherDetails\": {\n      \"narration\": \"Synthetic order from the web shop\",\n      \"transport\": \"Synthetic Transport Co\",\n      \"grNumber\": null,\n      \"vehicleNumber\": \"XX00ZZ0000\",\n      \"station\": null\n    },\n    \"salesman\": {\n      \"code\": 9701,\n      \"name\": \"Synthetic Salesman\"\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-invoices.create\",\n    \"requestId\": \"0d9f3a1c5b7e4f2a8c6d1e0b9a8f7e6d\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 2,\n    \"verification\": [\n      \"busyReadBack\",\n      \"savedRows\"\n    ],\n    \"elapsedMs\": 6240,\n    \"executedAt\": \"2026-10-14T06:30:00+00:00\"\n  }\n}"},{"id":"b8880702-807f-c769-1a0e-d902f59395d6","name":"200 – salesman explicitly null (synthetic Local; native default)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 2,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Postman test line\"\n      ]\n    },\n    {\n      \"item\": {\n        \"name\": \"Parle G\"\n      },\n      \"quantity\": 2.5,\n      \"rate\": 20.1\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"salesman\": null\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"invoiceId\": 8802,\n    \"invoiceNumber\": \"21/2026-27\",\n    \"invoiceReference\": \"WEB-INV-20481\",\n    \"date\": \"2026-10-14\",\n    \"voucherSeries\": {\n      \"code\": 258,\n      \"name\": \"Main\"\n    },\n    \"customer\": {\n      \"code\": 7001,\n      \"name\": \"Synthetic Traders\"\n    },\n    \"saleType\": {\n      \"code\": 1223,\n      \"name\": \"Local-ItemWise\"\n    },\n    \"taxation\": \"local\",\n    \"materialCenter\": {\n      \"code\": 201,\n      \"name\": \"Main Store\"\n    },\n    \"lines\": [\n      {\n        \"lineNumber\": 1,\n        \"item\": {\n          \"code\": 9401,\n          \"name\": \"Synthetic Item\"\n        },\n        \"unit\": \"Pcs.\",\n        \"quantity\": 3,\n        \"rate\": 150,\n        \"discountPercent\": 10,\n        \"netRate\": 135,\n        \"taxableAmount\": 405,\n        \"cgst\": 24.3,\n        \"sgst\": 24.3,\n        \"igst\": 0,\n        \"taxAmount\": 48.6,\n        \"amount\": 453.6,\n        \"mrp\": 210,\n        \"description\": [\n          \"Synthetic description\"\n        ]\n      },\n      {\n        \"lineNumber\": 2,\n        \"item\": {\n          \"code\": 9402,\n          \"name\": \"Synthetic Biscuits\"\n        },\n        \"unit\": \"Pcs.\",\n        \"quantity\": 2.5,\n        \"rate\": 20.1,\n        \"discountPercent\": 0,\n        \"netRate\": 20.1,\n        \"taxableAmount\": 50.25,\n        \"cgst\": 4.52,\n        \"sgst\": 4.52,\n        \"igst\": 0,\n        \"taxAmount\": 9.04,\n        \"amount\": 59.29,\n        \"mrp\": null,\n        \"description\": []\n      }\n    ],\n    \"totals\": {\n      \"quantity\": 5.5,\n      \"taxableAmount\": 455.25,\n      \"cgst\": 28.82,\n      \"sgst\": 28.82,\n      \"igst\": 0,\n      \"taxAmount\": 57.64,\n      \"amount\": 512.89\n    },\n    \"ledger\": [\n      {\n        \"account\": {\n          \"code\": 7001,\n          \"name\": \"Synthetic Traders\"\n        },\n        \"debit\": 512.89,\n        \"credit\": 0\n      },\n      {\n        \"account\": {\n          \"code\": 4,\n          \"name\": \"Sales\"\n        },\n        \"debit\": 0,\n        \"credit\": 455.25\n      },\n      {\n        \"account\": {\n          \"code\": 1142,\n          \"name\": \"CGST Output\"\n        },\n        \"debit\": 0,\n        \"credit\": 28.82\n      },\n      {\n        \"account\": {\n          \"code\": 1141,\n          \"name\": \"SGST Output\"\n        },\n        \"debit\": 0,\n        \"credit\": 28.82\n      }\n    ],\n    \"billReference\": {\n      \"number\": \"21/2026-27\",\n      \"dueDate\": \"2026-10-29\",\n      \"amount\": 512.89,\n      \"dueDateSource\": \"creditDays\"\n    },\n    \"billing\": {\n      \"source\": \"customer\",\n      \"name\": \"Synthetic Traders\",\n      \"address1\": \"1 Example Road\",\n      \"address2\": \"Example Town\",\n      \"address3\": null,\n      \"address4\": null,\n      \"mobile\": \"9000000001\",\n      \"email\": null,\n      \"gstNumber\": null,\n      \"panNumber\": null,\n      \"state\": \"Madhya Pradesh\"\n    },\n    \"otherDetails\": {\n      \"narration\": \"Synthetic order from the web shop\",\n      \"transport\": \"Synthetic Transport Co\",\n      \"grNumber\": null,\n      \"vehicleNumber\": \"XX00ZZ0000\",\n      \"station\": null\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-invoices.create\",\n    \"requestId\": \"0d9f3a1c5b7e4f2a8c6d1e0b9a8f7e6d\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 2,\n    \"verification\": [\n      \"busyReadBack\",\n      \"savedRows\"\n    ],\n    \"elapsedMs\": 6240,\n    \"executedAt\": \"2026-10-14T06:30:00+00:00\"\n  }\n}"},{"id":"05c74039-534c-3e1a-ba43-c10081d84176","name":"409 – SALESMAN_CONFIGURATION_UNSUPPORTED (synthetic; nothing saved)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 2,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Postman test line\"\n      ]\n    },\n    {\n      \"item\": {\n        \"name\": \"Parle G\"\n      },\n      \"quantity\": 2.5,\n      \"rate\": 20.1\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"salesman\": {\n    \"code\": 9701\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SALESMAN_CONFIGURATION_UNSUPPORTED\",\n      \"message\": \"The company does not support the requested voucher-level salesman assignment.\",\n      \"field\": \"salesman\"\n    }\n  }\n}"},{"id":"f730ec09-4152-c26a-2e9b-b0bba2f65ec0","name":"409 – SALESMAN_CONFIGURATION_CHANGED (synthetic; nothing saved)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 2,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Postman test line\"\n      ]\n    },\n    {\n      \"item\": {\n        \"name\": \"Parle G\"\n      },\n      \"quantity\": 2.5,\n      \"rate\": 20.1\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"salesman\": {\n    \"code\": 9701\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SALESMAN_CONFIGURATION_CHANGED\",\n      \"message\": \"The salesman or its configuration changed before save; nothing was saved.\",\n      \"field\": \"salesman\"\n    }\n  }\n}"},{"id":"84ae9909-d507-1a99-724c-9d07046ad0b6","name":"422 – MASTER_REFERENCE_NOT_FOUND salesman (synthetic; nothing saved)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 2,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Postman test line\"\n      ]\n    },\n    {\n      \"item\": {\n        \"name\": \"Parle G\"\n      },\n      \"quantity\": 2.5,\n      \"rate\": 20.1\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"salesman\": {\n    \"code\": 999999\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"MASTER_REFERENCE_NOT_FOUND\",\n      \"message\": \"No salesman with that code or name exists in this company and financial year.\",\n      \"field\": \"salesman\"\n    }\n  }\n}"},{"id":"e1182361-61fe-46e9-b7bd-c85cb47514a1","name":"409 - BUSY_WRITE_REFERENCE_IN_PROGRESS (synthetic; before save)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"BUSY_WRITE_REFERENCE_IN_PROGRESS\",\"field\":\"invoiceReference\",\"message\":\"Another write owns this business reference. Wait for its result; do not resend under a different request ID.\"}}}"},{"id":"4e43b2c2-89cf-4524-853d-21e156eae38c","name":"409 - BUSY_WRITE_REFERENCE_REVIEW_REQUIRED (synthetic; before save)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"BUSY_WRITE_REFERENCE_REVIEW_REQUIRED\",\"field\":\"invoiceReference\",\"message\":\"An earlier write with this business reference needs read-only reconciliation. Do not repost it. Use its existing job/result and retain the original reference.\"}}}"},{"id":"b3399985-0de6-4848-9719-73be96344708","name":"503 - BUSY_WRITE_ADMISSION_UNAVAILABLE (synthetic; review prior result)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"Service Unavailable","code":503,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"metadata\":{\"error\":{\"message\":\"Durable write admission could not be confirmed. Retain the reference and review the previous result.\",\"code\":\"BUSY_WRITE_ADMISSION_UNAVAILABLE\"}},\"success\":false,\"data\":null}"},{"id":"1f5c6f34-02cb-4b2e-8684-61ab40cfa9d1","name":"409 - BUSY_WRITE_TARGET_CHANGED (synthetic; before save)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/sales-invoice-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"BUSY_WRITE_TARGET_CHANGED\",\"message\":\"The BUSY destination or its permissions changed before helper execution; nothing was saved.\"}}}"}],"_postman_id":"a8cc6684-520c-a2f6-2416-345f629263ff"},{"name":"⚠ BUSY receipt – create (writes to BUSY)","id":"2616df47-f54c-0267-b4bd-12ea1367f5ca","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"receiptReference\": \"{{receiptReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"party\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"amount\": 100,\n  \"instrumentNumber\": \"SYNTHETIC-001\",\n  \"shortNarration\": \"Postman test receipt\",\n  \"narration\": \"Postman test receipt (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/receipt-create","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/receipt-create</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>⚠ Writes to BUSY</strong> (Development Local Send requires no separate confirmation)\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>receiptReference</code>, <code>date</code>, <code>account</code>, <code>party</code>, <code>amount</code> · operation <code>busy.receipts.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq). The series must number automatically (<code>422 RECEIPT_SERIES_UNSUPPORTED</code>).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books. Run manually, one at a time.</strong> <code>busy.receipts.create</code> (<code>POST /api/v1/receipt-create</code>) creates one BUSY <strong>receipt</strong> through BUSY's own COM component on this PC: <strong>one</strong> cash-in-hand, bank or bank OD <code>account</code> received into (debited) and <strong>one</strong> paying <code>party</code> (credited). <strong>Create only</strong>: it never changes, cancels or deletes a receipt. <strong>SQL Server companies with a SQL login, or Access companies</strong>. Never run from scripts. <strong>Status:</strong> implemented 2026-10-14; installed service-account acceptance passed 2026-10-15 (receipts 82-85 on COMP0002 / 2026); owner acceptance for customers is separate. <strong>Through the cloud: not available</strong> — Windows relays it with the write rules (same organization token), but the AI Zeny cloud has no <code>/v1/receipt-create</code> route yet; see <code>docs/integration/Cloud-Receipt-Relay-Handoff.md</code>.</p>\n<p><strong>How it works.</strong> BUSY numbers the receipt from the series. Your <code>receiptReference</code> (1-60) is stored in the first narration and must be unique among the company's receipts of the year; <code>narration</code> goes to the second narration. Optional <code>allocations</code> (1-100, together at most <code>amount</code>): <code>{\"bill\": {\"number\": \"…\"}, \"amount\": n}</code> settles one of the <strong>party's own outstanding bills</strong> (at most what it still owes), <code>{\"newReference\": {\"number\": \"…\", \"dueDate\": \"YYYY-MM-DD\"}, \"amount\": n}</code> opens an advance (a number the party does not use yet). Whatever is not allocated stays <strong>on account</strong> (<code>data.unallocatedAmount</code>). Allocations only for a party BUSY keeps bill by bill. AI Zeny compares BUSY's read-back, the saved rows and each settled bill's outstanding amount before answering. One receipt create at a time on the PC.</p>\n<p><strong>Refused before BUSY (BUSY's own import would accept them):</strong> an unknown party name (<code>422 MASTER_REFERENCE_NOT_FOUND</code>; BUSY would create the account), a bill the party does not owe or another party's bill (<code>422 RECEIPT_BILL_NOT_FOUND</code>, <code>field</code> <code>allocations[i].bill.number</code>), over-settlement (<code>422 RECEIPT_BILL_OVERSETTLED</code>, <code>field</code> <code>allocations[i].amount</code>), a reused reference number (<code>409 RECEIPT_NEW_REFERENCE_TAKEN</code>), allocations above the amount or more than 2 decimals (<code>400</code>), a receiving account that is not cash/bank/OD or a cash/bank party (<code>422 RECEIPT_ACCOUNT_UNSUPPORTED</code>), allocations for a party not kept bill by bill (<code>422 RECEIPT_ALLOCATION_UNSUPPORTED</code>). An instrument type is not accepted (its meanings are not proven); <code>instrumentNumber</code> (1-30) is.</p>\n<p><strong>Safe test guidance</strong></p>\n<ul>\n<li>Select a development-test <code>companyCode</code> (<code>COMP0002</code> / FY 2026 in this environment; use <code>COMP0001</code> for Access tests). With <code>autoVoucherReferences=yes</code>, each Local Send generates and stores a fresh 25-character synthetic <code>receiptReference</code>. Set that switch to <code>no</code> to supply your own unique reference. Do not reuse <code>AZPOC-RC-…</code> or <code>AZSVC-RC-…</code> (earlier test records).</li>\n<li>The example body is an <strong>on-account</strong> receipt (no allocation), so it never depends on a bill that may already be settled. To settle a bill, add <code>allocations</code> with a PoC test bill of the test customer (never an <code>AZSVC-SI-…</code> acceptance invoice).</li>\n<li>Nothing is deleted automatically: a created test receipt stays in BUSY.</li>\n<li><strong>Never retry blindly.</strong> Automatic references change on each Send, so another Send can create another voucher; reconcile an uncertain result first. Sending the same <code>receiptReference</code> again is refused (<code>409 RECEIPT_REFERENCE_TAKEN</code>, <code>details.receiptId</code>) if the first send saved. After <code>504 BUSY_WRITE_UNCERTAIN</code>, read <code>metadata.error.details.reconciliation</code> (<code>found</code> + <code>receiptId</code>, <code>notFound</code>, <code>notChecked</code>) and check BUSY first.</li>\n<li><code>502 BUSY_WRITE_UNVERIFIED</code> means BUSY <strong>did</strong> save but its read-back or a settled bill differs (<code>details.receiptId</code>, <code>details.mismatchedFields</code>).</li>\n<li>One BUSY job at a time on the PC (shared with voucher PDFs, invoices, orders and master writes), up to 2 minutes: give the request a long timeout.</li>\n</ul>\n<p><strong>Sets:</strong> <code>receiptId</code> on success (usable as <code>voucherId</code> with <code>voucherType</code> <code>receipt</code> in the Voucher PDF request). Public guide: <code>docs/public/api/receipt-create.md</code>.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n<p>Original destination: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Installed public v0.0.30 predates this merged source; these are documentation examples only. Do not Send until a newer candidate with this source is installed and the target BUSY series is verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"receiptReference\": \"{{receiptReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"account\": {\n    \"name\": \"Cash\"\n  },\n  \"party\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"amount\": 100,\n  \"instrumentNumber\": \"SYNTHETIC-001\",\n  \"shortNarration\": \"Postman test receipt\",\n  \"narration\": \"Postman test receipt (on account)\",\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"receiptReference\": \"{{receiptReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"account\": {\n    \"name\": \"Cash\"\n  },\n  \"party\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"amount\": 100,\n  \"instrumentNumber\": \"SYNTHETIC-001\",\n  \"shortNarration\": \"Postman test receipt\",\n  \"narration\": \"Postman test receipt (on account)\",\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","receipt-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"6157fa87-b34f-6fa5-f61e-a7ed5c4540a3","name":"200 created — two bills settled, an advance, the rest on account (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"receiptReference\": \"{{receiptReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"party\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"amount\": 100,\n  \"instrumentNumber\": \"SYNTHETIC-001\",\n  \"shortNarration\": \"Postman test receipt\",\n  \"narration\": \"Postman test receipt (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/receipt-create","description":"**Local** · `POST {{baseUrl}}/api/v1/receipt-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (Development Local Send requires no separate confirmation)\n**Required:** `companyCode`, `financialYear`, `receiptReference`, `date`, `account`, `party`, `amount` · operation `busy.receipts.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). The series must number automatically (`422 RECEIPT_SERIES_UNSUPPORTED`).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.receipts.create` (`POST /api/v1/receipt-create`) creates one BUSY **receipt** through BUSY's own COM component on this PC: **one** cash-in-hand, bank or bank OD `account` received into (debited) and **one** paying `party` (credited). **Create only**: it never changes, cancels or deletes a receipt. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-14; installed service-account acceptance passed 2026-10-15 (receipts 82-85 on COMP0002 / 2026); owner acceptance for customers is separate. **Through the cloud: not available** — Windows relays it with the write rules (same organization token), but the AI Zeny cloud has no `/v1/receipt-create` route yet; see `docs/integration/Cloud-Receipt-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the receipt from the series. Your `receiptReference` (1-60) is stored in the first narration and must be unique among the company's receipts of the year; `narration` goes to the second narration. Optional `allocations` (1-100, together at most `amount`): `{\"bill\": {\"number\": \"…\"}, \"amount\": n}` settles one of the **party's own outstanding bills** (at most what it still owes), `{\"newReference\": {\"number\": \"…\", \"dueDate\": \"YYYY-MM-DD\"}, \"amount\": n}` opens an advance (a number the party does not use yet). Whatever is not allocated stays **on account** (`data.unallocatedAmount`). Allocations only for a party BUSY keeps bill by bill. AI Zeny compares BUSY's read-back, the saved rows and each settled bill's outstanding amount before answering. One receipt create at a time on the PC.\n\n**Refused before BUSY (BUSY's own import would accept them):** an unknown party name (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create the account), a bill the party does not owe or another party's bill (`422 RECEIPT_BILL_NOT_FOUND`, `field` `allocations[i].bill.number`), over-settlement (`422 RECEIPT_BILL_OVERSETTLED`, `field` `allocations[i].amount`), a reused reference number (`409 RECEIPT_NEW_REFERENCE_TAKEN`), allocations above the amount or more than 2 decimals (`400`), a receiving account that is not cash/bank/OD or a cash/bank party (`422 RECEIPT_ACCOUNT_UNSUPPORTED`), allocations for a party not kept bill by bill (`422 RECEIPT_ALLOCATION_UNSUPPORTED`). An instrument type is not accepted (its meanings are not proven); `instrumentNumber` (1-30) is.\n\n**Safe test guidance**\n- Select a development-test `companyCode` (`COMP0002` / FY 2026 in this environment; use `COMP0001` for Access tests). With `autoVoucherReferences=yes`, each Local Send generates and stores a fresh 25-character synthetic `receiptReference`. Set that switch to `no` to supply your own unique reference. Do not reuse `AZPOC-RC-…` or `AZSVC-RC-…` (earlier test records).\n- The example body is an **on-account** receipt (no allocation), so it never depends on a bill that may already be settled. To settle a bill, add `allocations` with a PoC test bill of the test customer (never an `AZSVC-SI-…` acceptance invoice).\n- Nothing is deleted automatically: a created test receipt stays in BUSY.\n- **Never retry blindly.** Automatic references change on each Send, so another Send can create another voucher; reconcile an uncertain result first. Sending the same `receiptReference` again is refused (`409 RECEIPT_REFERENCE_TAKEN`, `details.receiptId`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `receiptId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back or a settled bill differs (`details.receiptId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs, invoices, orders and master writes), up to 2 minutes: give the request a long timeout.\n\n**Sets:** `receiptId` on success (usable as `voucherId` with `voucherType` `receipt` in the Voucher PDF request). Public guide: `docs/public/api/receipt-create.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\r\n\r\nOriginal destination: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"receiptId\": 8810,\n    \"receiptNumber\": \"23\",\n    \"receiptReference\": \"WEB-RCPT-30155\",\n    \"date\": \"2026-10-14\",\n    \"voucherSeries\": { \"code\": 263, \"name\": \"Main\" },\n    \"account\": { \"code\": 9001, \"name\": \"Synthetic Bank\" },\n    \"party\": { \"code\": 7001, \"name\": \"Synthetic Traders\" },\n    \"amount\": 1000,\n    \"allocations\": [\n      { \"type\": \"bill\", \"number\": \"INV-21\", \"amount\": 512.89, \"dueDate\": \"2026-10-29\", \"outstandingBefore\": 512.89, \"outstandingAfter\": 0 },\n      { \"type\": \"bill\", \"number\": \"INV-23\", \"amount\": 300, \"dueDate\": \"2026-10-31\", \"outstandingBefore\": 1120, \"outstandingAfter\": 820 },\n      { \"type\": \"newReference\", \"number\": \"ADV-30155\", \"amount\": 150, \"dueDate\": \"2026-11-30\", \"outstandingBefore\": null, \"outstandingAfter\": null }\n    ],\n    \"allocatedAmount\": 962.89,\n    \"unallocatedAmount\": 37.11,\n    \"instrumentNumber\": \"SYN000123\",\n    \"shortNarration\": \"Synthetic cheque\",\n    \"narration\": \"Synthetic payment from the web shop\",\n    \"ledger\": [\n      { \"account\": { \"code\": 9001, \"name\": \"Synthetic Bank\" }, \"debit\": 1000, \"credit\": 0 },\n      { \"account\": { \"code\": 7001, \"name\": \"Synthetic Traders\" }, \"debit\": 0, \"credit\": 1000 }\n    ]\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.receipts.create\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e10\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"allocationCount\": 3,\n    \"verification\": [\"busyReadBack\", \"savedRows\"],\n    \"elapsedMs\": 2310,\n    \"executedAt\": \"2026-09-26T10:00:00+00:00\"\n  }\n}"},{"id":"3ff70d64-8463-711e-28ae-abfbbf6a3f2f","name":"409 RECEIPT_REFERENCE_TAKEN — a repeat after a saved receipt (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"receiptReference\": \"{{receiptReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"party\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"amount\": 100,\n  \"instrumentNumber\": \"SYNTHETIC-001\",\n  \"shortNarration\": \"Postman test receipt\",\n  \"narration\": \"Postman test receipt (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/receipt-create","description":"**Local** · `POST {{baseUrl}}/api/v1/receipt-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (Development Local Send requires no separate confirmation)\n**Required:** `companyCode`, `financialYear`, `receiptReference`, `date`, `account`, `party`, `amount` · operation `busy.receipts.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). The series must number automatically (`422 RECEIPT_SERIES_UNSUPPORTED`).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.receipts.create` (`POST /api/v1/receipt-create`) creates one BUSY **receipt** through BUSY's own COM component on this PC: **one** cash-in-hand, bank or bank OD `account` received into (debited) and **one** paying `party` (credited). **Create only**: it never changes, cancels or deletes a receipt. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-14; installed service-account acceptance passed 2026-10-15 (receipts 82-85 on COMP0002 / 2026); owner acceptance for customers is separate. **Through the cloud: not available** — Windows relays it with the write rules (same organization token), but the AI Zeny cloud has no `/v1/receipt-create` route yet; see `docs/integration/Cloud-Receipt-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the receipt from the series. Your `receiptReference` (1-60) is stored in the first narration and must be unique among the company's receipts of the year; `narration` goes to the second narration. Optional `allocations` (1-100, together at most `amount`): `{\"bill\": {\"number\": \"…\"}, \"amount\": n}` settles one of the **party's own outstanding bills** (at most what it still owes), `{\"newReference\": {\"number\": \"…\", \"dueDate\": \"YYYY-MM-DD\"}, \"amount\": n}` opens an advance (a number the party does not use yet). Whatever is not allocated stays **on account** (`data.unallocatedAmount`). Allocations only for a party BUSY keeps bill by bill. AI Zeny compares BUSY's read-back, the saved rows and each settled bill's outstanding amount before answering. One receipt create at a time on the PC.\n\n**Refused before BUSY (BUSY's own import would accept them):** an unknown party name (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create the account), a bill the party does not owe or another party's bill (`422 RECEIPT_BILL_NOT_FOUND`, `field` `allocations[i].bill.number`), over-settlement (`422 RECEIPT_BILL_OVERSETTLED`, `field` `allocations[i].amount`), a reused reference number (`409 RECEIPT_NEW_REFERENCE_TAKEN`), allocations above the amount or more than 2 decimals (`400`), a receiving account that is not cash/bank/OD or a cash/bank party (`422 RECEIPT_ACCOUNT_UNSUPPORTED`), allocations for a party not kept bill by bill (`422 RECEIPT_ALLOCATION_UNSUPPORTED`). An instrument type is not accepted (its meanings are not proven); `instrumentNumber` (1-30) is.\n\n**Safe test guidance**\n- Select a development-test `companyCode` (`COMP0002` / FY 2026 in this environment; use `COMP0001` for Access tests). With `autoVoucherReferences=yes`, each Local Send generates and stores a fresh 25-character synthetic `receiptReference`. Set that switch to `no` to supply your own unique reference. Do not reuse `AZPOC-RC-…` or `AZSVC-RC-…` (earlier test records).\n- The example body is an **on-account** receipt (no allocation), so it never depends on a bill that may already be settled. To settle a bill, add `allocations` with a PoC test bill of the test customer (never an `AZSVC-SI-…` acceptance invoice).\n- Nothing is deleted automatically: a created test receipt stays in BUSY.\n- **Never retry blindly.** Automatic references change on each Send, so another Send can create another voucher; reconcile an uncertain result first. Sending the same `receiptReference` again is refused (`409 RECEIPT_REFERENCE_TAKEN`, `details.receiptId`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `receiptId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back or a settled bill differs (`details.receiptId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs, invoices, orders and master writes), up to 2 minutes: give the request a long timeout.\n\n**Sets:** `receiptId` on success (usable as `voucherId` with `voucherType` `receipt` in the Voucher PDF request). Public guide: `docs/public/api/receipt-create.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\r\n\r\nOriginal destination: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"RECEIPT_REFERENCE_TAKEN\",\n      \"message\": \"A receipt of this company and financial year already holds this receiptReference. A create never changes an existing receipt; if your earlier call saved it, metadata.error.details.receiptId names it.\",\n      \"field\": \"receiptReference\",\n      \"details\": { \"receiptId\": 8810 }\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e11\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"7a614909-ca4c-fdb2-96e6-fb951c500d35","name":"422 RECEIPT_BILL_NOT_FOUND — not a bill this party owes (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"receiptReference\": \"{{receiptReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"party\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"amount\": 100,\n  \"instrumentNumber\": \"SYNTHETIC-001\",\n  \"shortNarration\": \"Postman test receipt\",\n  \"narration\": \"Postman test receipt (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/receipt-create","description":"**Local** · `POST {{baseUrl}}/api/v1/receipt-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (Development Local Send requires no separate confirmation)\n**Required:** `companyCode`, `financialYear`, `receiptReference`, `date`, `account`, `party`, `amount` · operation `busy.receipts.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). The series must number automatically (`422 RECEIPT_SERIES_UNSUPPORTED`).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.receipts.create` (`POST /api/v1/receipt-create`) creates one BUSY **receipt** through BUSY's own COM component on this PC: **one** cash-in-hand, bank or bank OD `account` received into (debited) and **one** paying `party` (credited). **Create only**: it never changes, cancels or deletes a receipt. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-14; installed service-account acceptance passed 2026-10-15 (receipts 82-85 on COMP0002 / 2026); owner acceptance for customers is separate. **Through the cloud: not available** — Windows relays it with the write rules (same organization token), but the AI Zeny cloud has no `/v1/receipt-create` route yet; see `docs/integration/Cloud-Receipt-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the receipt from the series. Your `receiptReference` (1-60) is stored in the first narration and must be unique among the company's receipts of the year; `narration` goes to the second narration. Optional `allocations` (1-100, together at most `amount`): `{\"bill\": {\"number\": \"…\"}, \"amount\": n}` settles one of the **party's own outstanding bills** (at most what it still owes), `{\"newReference\": {\"number\": \"…\", \"dueDate\": \"YYYY-MM-DD\"}, \"amount\": n}` opens an advance (a number the party does not use yet). Whatever is not allocated stays **on account** (`data.unallocatedAmount`). Allocations only for a party BUSY keeps bill by bill. AI Zeny compares BUSY's read-back, the saved rows and each settled bill's outstanding amount before answering. One receipt create at a time on the PC.\n\n**Refused before BUSY (BUSY's own import would accept them):** an unknown party name (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create the account), a bill the party does not owe or another party's bill (`422 RECEIPT_BILL_NOT_FOUND`, `field` `allocations[i].bill.number`), over-settlement (`422 RECEIPT_BILL_OVERSETTLED`, `field` `allocations[i].amount`), a reused reference number (`409 RECEIPT_NEW_REFERENCE_TAKEN`), allocations above the amount or more than 2 decimals (`400`), a receiving account that is not cash/bank/OD or a cash/bank party (`422 RECEIPT_ACCOUNT_UNSUPPORTED`), allocations for a party not kept bill by bill (`422 RECEIPT_ALLOCATION_UNSUPPORTED`). An instrument type is not accepted (its meanings are not proven); `instrumentNumber` (1-30) is.\n\n**Safe test guidance**\n- Select a development-test `companyCode` (`COMP0002` / FY 2026 in this environment; use `COMP0001` for Access tests). With `autoVoucherReferences=yes`, each Local Send generates and stores a fresh 25-character synthetic `receiptReference`. Set that switch to `no` to supply your own unique reference. Do not reuse `AZPOC-RC-…` or `AZSVC-RC-…` (earlier test records).\n- The example body is an **on-account** receipt (no allocation), so it never depends on a bill that may already be settled. To settle a bill, add `allocations` with a PoC test bill of the test customer (never an `AZSVC-SI-…` acceptance invoice).\n- Nothing is deleted automatically: a created test receipt stays in BUSY.\n- **Never retry blindly.** Automatic references change on each Send, so another Send can create another voucher; reconcile an uncertain result first. Sending the same `receiptReference` again is refused (`409 RECEIPT_REFERENCE_TAKEN`, `details.receiptId`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `receiptId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back or a settled bill differs (`details.receiptId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs, invoices, orders and master writes), up to 2 minutes: give the request a long timeout.\n\n**Sets:** `receiptId` on success (usable as `voucherId` with `voucherType` `receipt` in the Voucher PDF request). Public guide: `docs/public/api/receipt-create.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n\r\n\r\nOriginal destination: 409 BUSY_WRITE_TARGET_CHANGED means the original company/FY/provider destination or permissions changed after preflight and native save was refused. Preserve the original target and any known job/voucher ID. A 202 queue answer is acceptance only; 502/504 or unknown outcomes require read-only reconciliation and must never be automatically reposted. Transport X-Request-Id is not a business reference. These are Local source contracts and synthetic examples, not installed-service or Cloud proof."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"RECEIPT_BILL_NOT_FOUND\",\n      \"message\": \"This number is not an outstanding bill of the paying party in BUSY (a receivable it still owes). Check the bill's number, or send the amount as a new reference or leave it on account.\",\n      \"field\": \"allocations[0].bill.number\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e12\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"dc03e58c-8ead-d2a4-277c-55b6047aba20","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"receiptReference\": \"{{receiptReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"account\": {\n    \"name\": \"Cash\"\n  },\n  \"party\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"amount\": 100,\n  \"instrumentNumber\": \"SYNTHETIC-001\",\n  \"shortNarration\": \"Postman test receipt\",\n  \"narration\": \"Postman test receipt (on account)\",\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/receipt-create"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"},{"value":"synthetic-queue-001","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.receipts.create\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"},{"id":"ef20d264-9833-4082-ba3d-ddbf4200261f","name":"409 - BUSY_WRITE_TARGET_CHANGED (synthetic; before save)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/receipt-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"BUSY_WRITE_TARGET_CHANGED\",\"message\":\"The BUSY destination or its permissions changed before helper execution; nothing was saved.\"}}}"}],"_postman_id":"2616df47-f54c-0267-b4bd-12ea1367f5ca"},{"name":"⚠ BUSY sales return – create (writes to BUSY)","id":"38158799-3dd8-030c-c907-896163fdd269","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 150, \"description\": [\"Postman test return\"] }\n  ],\n  \"narration\": \"Postman test sales return (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/sales-return-create</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>⚠ Writes to BUSY</strong> (Development Local Send requires no separate confirmation)\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>returnReference</code>, <code>date</code>, <code>customer</code>, <code>saleType</code>, <code>materialCenter</code>, <code>lines</code> · <strong>Optional:</strong> <code>voucherSeries</code>, <code>originalInvoice</code>, <code>adjustment</code>, <code>narration</code> · operation <code>busy.sales-returns.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq). The series must number automatically (<code>422 SALES_RETURN_SERIES_UNSUPPORTED</code>).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books. Run manually, one at a time.</strong> <code>busy.sales-returns.create</code> (<code>POST /api/v1/sales-return-create</code>) creates one BUSY <strong>sales return (credit note)</strong> through BUSY's own COM component on this PC: the reverse of a sale — the customer is credited, the sales and GST accounts debited, the goods come back into <code>materialCenter</code>. <strong>Create only</strong>: it never changes, cancels or deletes a return or an invoice. <strong>SQL Server companies with a SQL login, or Access companies</strong>. Never run from scripts. <strong>Status:</strong> implemented 2026-10-15; installed service-account acceptance <strong>passed</strong> 2026-10-15 (COMP0002 / 2026, returns 110-113 and nine refusals that wrote nothing; contract section 9); owner acceptance for customers is separate. <strong>Through the cloud: not available</strong> — Windows relays it with the write rules (same organization token), but the AI Zeny cloud has no <code>/v1/sales-return-create</code> route yet (it will be added together with the receipt route); see <code>docs/integration/Cloud-Sales-Return-Relay-Handoff.md</code>.</p>\n<p><strong>How it works.</strong> BUSY numbers the return from the series. Your <code>returnReference</code> (1-60) is stored in the first narration and must be unique among the company's sales returns of the year (BUSY's own included); <code>narration</code> goes to the second narration. <code>lines</code> (1-100): <code>item</code>, <code>quantity</code> (main unit, <strong>at most 2 decimals</strong>), <code>rate</code>, optional <code>discountPercent</code>, <code>mrp</code>, <code>description</code>; AI Zeny calculates GST as for a sales invoice (matching item-wise sale types; tracked items refused).</p>\n<ul>\n<li><code>originalInvoice</code> (optional): <code>{\"voucherId\": n}</code> or <code>{\"number\": \"…\"}</code> — the customer's own non-cancelled sales invoice of the year, dated on or before the return, same local/central kind. Its real number and date are recorded. No item may come back beyond what it sold less earlier non-cancelled returns naming it (BUSY's own included).</li>\n<li><code>adjustment</code> (optional, default on account): <code>{\"type\": \"onAccount\"}</code>, <code>{\"type\": \"againstOriginalInvoice\", \"amount\"?: n}</code> (reduces the invoice's own bill, never below zero; default the smaller of the return amount and the outstanding amount) or <code>{\"type\": \"newReference\", \"number\": \"…\", \"dueDate\"?: \"YYYY-MM-DD\", \"amount\"?: n}</code> (a credit reference with a number new to the customer). The rest stays on account (<code>data.unallocatedAmount</code>). Adjustments only for a customer BUSY keeps bill by bill.</li>\n<li>AI Zeny compares BUSY's read-back, the saved rows (reversed signs, stock back in) and the adjusted bill before answering. Receipts and sales returns share one lock on the PC.</li>\n</ul>\n<p><strong>Refused before BUSY (BUSY's own import would accept them):</strong> an unknown master name (<code>422 MASTER_REFERENCE_NOT_FOUND</code>; BUSY would create it), another customer's invoice (<code>422 SALES_RETURN_ORIGINAL_MISMATCH</code>), a cancelled one (<code>422 SALES_RETURN_ORIGINAL_CANCELLED</code>), a number shared by several of the customer's invoices (<code>422 SALES_RETURN_ORIGINAL_AMBIGUOUS</code> — send <code>voucherId</code>), more than was sold less earlier returns (<code>422 SALES_RETURN_QUANTITY_EXCEEDS_SALE</code>, <code>field</code> <code>lines[i].quantity</code> or <code>lines[i].item</code>), history that cannot be tied to the invoice (<code>422 SALES_RETURN_HISTORY_AMBIGUOUS</code>), over-settlement (<code>422 SALES_RETURN_BILL_OVERSETTLED</code>), a settled or missing bill (<code>422 SALES_RETURN_BILL_NOT_FOUND</code>), a reused reference number (<code>409 SALES_RETURN_NEW_REFERENCE_TAKEN</code>), a tracked item (<code>422 SALES_RETURN_ITEM_UNSUPPORTED</code>), 3 decimals (<code>400</code>). A return number, billing block or XML is never accepted; Manual monetary amounts follow the GST billing-mode contract (<code>400</code>).</p>\n<p><strong>Safe test guidance</strong></p>\n<ul>\n<li>Select a development-test <code>companyCode</code> (<code>COMP0002</code> / FY 2026 in this environment; use <code>COMP0001</code> for Access tests). With <code>autoVoucherReferences=yes</code>, each Local Send generates and stores a fresh 25-character synthetic <code>returnReference</code>. Set that switch to <code>no</code> to supply your own unique reference. Do not reuse <code>AZPOC-SR-…</code> or <code>AZSVC-SR-…</code> (earlier test records, including the acceptance's invoices 106-108 and returns 110-113).</li>\n<li>The example body is a <strong>standalone on-account</strong> return (no original invoice, no adjustment), so it never depends on an invoice's remaining quantity or bill. To link an invoice, add <code>originalInvoice</code> with a fresh test invoice of the same customer (never a PoC or acceptance invoice).</li>\n<li>Nothing is deleted automatically: a created test return stays in BUSY (and moves stock back in).</li>\n<li><strong>Never retry blindly.</strong> Automatic references change on each Send, so another Send can create another voucher; reconcile an uncertain result first. Sending the same <code>returnReference</code> again is refused (<code>409 SALES_RETURN_REFERENCE_TAKEN</code>, <code>details.returnId</code>) if the first send saved. After <code>504 BUSY_WRITE_UNCERTAIN</code>, read <code>metadata.error.details.reconciliation</code> (<code>found</code> + <code>returnId</code>, <code>notFound</code>, <code>notChecked</code>) and check BUSY first.</li>\n<li><code>502 BUSY_WRITE_UNVERIFIED</code> means BUSY <strong>did</strong> save but its read-back, saved rows or the adjusted bill differ (<code>details.returnId</code>, <code>details.mismatchedFields</code>).</li>\n<li>One BUSY job at a time on the PC (shared with voucher PDFs, receipts, invoices, orders and master writes), up to 2 minutes: give the request a long timeout. Body up to 128 KiB.</li>\n</ul>\n<p><strong>Sets:</strong> <code>returnId</code> on success (usable as <code>voucherId</code> with <code>voucherType</code> <code>salesReturn</code> in the Voucher PDF request). Public guide: <code>docs/public/api/sales-return-create.md</code>.</p>\n<p><strong>Line descriptions (owner acceptance 2026-10-19; <code>docs/features/BUSY-Voucher-Line-Descriptions.md</code>):</strong> <code>lines[].description</code> is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; <code>\"\"</code> or <code>null</code> keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise <code>422 BUSY_SETTING_REQUIRED</code> (<code>lines[i].description</code>) or <code>422 DESCRIPTION_LINE_NOT_ALLOWED</code> (<code>lines[i].description[n]</code>), nothing saved. SQL Server companies take Latin-1 characters only (<code>400</code>, before BUSY); Access companies any text. The answer's lines carry <code>description</code> as saved. Public guide: <code>docs/public/api/line-descriptions.md</code>.</p>\n<p><strong>GST billing modes (bounded internal 0.0.15 candidate accepted 2026-10-20 on Access and SQL Server; 0.0.16 release smoke was narrower):</strong> Optional <code>taxCalculation</code> is <code>auto</code> (default) or <code>manual</code>; optional <code>pricingMode</code> is <code>gstExclusive</code> (default) or <code>gstInclusive</code>. JSON <code>null</code> selects each default. One pricing mode applies to every line. <code>rate</code> is the unit price before discount, GST included only for <code>gstInclusive</code>; choose a native item-wise sale/purchase type whose inclusive setting matches. Tax rates come from each selected item's configured category for this company/year; local uses CGST+SGST, central uses IGST. Mixed-rate lines are allowed. Auto computes money using decimal arithmetic. Manual requires every line's <code>amounts</code> and document <code>totals</code>, each with <code>taxableAmount</code>, <code>cgst</code>, <code>sgst</code>, <code>igst</code>, <code>amount</code> (JSON numbers, max two decimals). <code>amount</code> equals taxable plus components; totals equal exact line sums. Local IGST and central CGST/SGST must be zero; submitted values must satisfy the narrow configured-rate and one-paisa bounds in <code>docs/features/BUSY-GST-Billing-Modes-Create-API.md</code>. No balancing charge or silent replacement. Returns submit positive amounts; BUSY posts reversal signs. Malformed JSON or unknown fields: <code>400 BAD_REQUEST</code>; missing or inconsistent Manual amounts: <code>400 INVALID_PARAMETER</code>; invalid configured-rate/treatment: <code>422 GST_AMOUNTS_INVALID</code>; unproven new-mode combination: <code>422 GST_MODE_UNSUPPORTED</code>; changed configuration before save: <code>409 GST_CONFIGURATION_CHANGED</code>. If saved read-back mismatches: <code>502 BUSY_WRITE_UNVERIFIED</code> means saved and requires reconciliation, never automatic retry. Linked returns and bill allocations, manual Purchase sundry discounts, and zero/exempt/nil treatment are not proven for new modes; existing Auto/exclusive supported flows remain. Cloud routes are not claimed deployed.</p>\n<p><strong>Mode payload examples</strong> (fragments; retain the route's company/year/date/reference/party/series/centre fields and use a matching configured native type):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\"taxCalculation\":\"auto\",\"pricingMode\":\"gstExclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 5% item\"},\"quantity\":1.25,\"rate\":10.10}]}\n{\"taxCalculation\":\"auto\",\"pricingMode\":\"gstInclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 18% item\"},\"quantity\":0.5,\"rate\":25.00}]}\n{\"taxCalculation\":\"manual\",\"pricingMode\":\"gstExclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 5% item\"},\"quantity\":1.25,\"rate\":10.10,\"amounts\":{\"taxableAmount\":12.62,\"cgst\":0.32,\"sgst\":0.32,\"igst\":0,\"amount\":13.26}}],\"totals\":{\"taxableAmount\":12.62,\"cgst\":0.32,\"sgst\":0.32,\"igst\":0,\"amount\":13.26}}\n{\"taxCalculation\":\"manual\",\"pricingMode\":\"gstInclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 18% item\"},\"quantity\":0.5,\"rate\":25.00,\"amounts\":{\"taxableAmount\":10.59,\"cgst\":0.96,\"sgst\":0.95,\"igst\":0,\"amount\":12.50}}],\"totals\":{\"taxableAmount\":10.59,\"cgst\":0.96,\"sgst\":0.95,\"igst\":0,\"amount\":12.50}}\n</code></pre>\n<p><strong>Mixed-rate Manual inclusive example:</strong> one 5% line may use a different configured tax category from an 18% line; sum every five amounts members exactly into totals. For central treatment replace both local components with IGST under the selected central native type. The one-paisa 18% example above shows the corrected CGST/SGST mapping. These are synthetic fragments, not live execution records.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n<h2 id=\"full-synthetic-gst-request-examples-local-only\">FULL synthetic GST request examples (Local only)</h2>\n<p>The raw Body tab above stays the minimal Auto/exclusive request. These separate complete bodies assume existing synthetic 5%/18% item tax categories, a matching item-wise native type, series, party and centre in the selected company/FY; replace fixture names and use a fresh reference before any send. <code>Local-TaxIncl.</code> must be configured with inclusive B13. Every line shares the voucher pricing mode. The amounts below are local CGST/SGST examples; for interstate treatment select the matching Central type and supply IGST instead. Return amounts remain positive in the request and BUSY reverses the postings. Do not infer Cloud Relay deployment from these Windows Local examples.</p>\n<p><strong>Auto + inclusive (synthetic FULL body):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstInclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-TaxIncl.\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic GST 18% Item\"\n      },\n      \"quantity\": 0.5,\n      \"rate\": 25\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\"\n}\n</code></pre>\n<p><strong>Manual + exclusive (synthetic FULL body):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic GST 5% Item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0,\n        \"amount\": 13.26\n      }\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\",\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0,\n    \"amount\": 13.26\n  }\n}\n</code></pre>\n<p><strong>Manual + inclusive (synthetic FULL body):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstInclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-TaxIncl.\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic GST 18% Item\"\n      },\n      \"quantity\": 0.5,\n      \"rate\": 25,\n      \"amounts\": {\n        \"taxableAmount\": 10.59,\n        \"cgst\": 0.96,\n        \"sgst\": 0.95,\n        \"igst\": 0,\n        \"amount\": 12.5\n      }\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\",\n  \"totals\": {\n    \"taxableAmount\": 10.59,\n    \"cgst\": 0.96,\n    \"sgst\": 0.95,\n    \"igst\": 0,\n    \"amount\": 12.5\n  }\n}\n</code></pre>\n<p>The normal request's test requires 200 for a synchronous success; saved 400/409/422/502/504 examples are separate expected-refusal illustrations and do not constitute a successful create assertion. An explicit queue:true request requires 202 and must be polled for its final result.</p>\n<h2 id=\"optional-salesman-local-source-synthetic-examples\">Optional salesman (Local source; synthetic examples)</h2>\n<p><code>salesman</code> is an optional voucher-header object: <code>{\"code\":9701}</code> or <code>{\"name\":\"Synthetic Salesman\"}</code>, exactly one key. It resolves an existing active MasterType-19 Salesman in the selected company/FY, distinct from an account with the same name. BUSY must have effective voucher-level salesman reporting enabled for the selected series. The chosen identity tags the header and every item line; it does not calculate or post commission. Replace synthetic identity and voucher fixtures before any guarded send.</p>\n<p>Omit <code>salesman</code> or send <code>null</code> to retain native default behavior and the existing response shape. A verified explicit assignment adds <code>data.salesman:{code,name}</code> last in a synchronous 200 result or a completed queued result. HTTP 202 only accepts a durable job; inspect its final result before claiming BUSY persistence. The existing 200 example omits salesman; separate saved synthetic examples show assignment and explicit null.</p>\n<p>Exact pre-save refusals: <code>409 SALESMAN_CONFIGURATION_UNSUPPORTED</code> (effective setting), <code>409 SALESMAN_CONFIGURATION_CHANGED</code> (selected identity or frozen configuration changed), and <code>409 BUSY_SETTINGS_UNREADABLE</code> (requested settings unreadable), each with <code>metadata.error.field:\"salesman\"</code>. Unknown or wrong-master-type code/name is <code>422 MASTER_REFERENCE_NOT_FOUND</code>; a duplicate ambiguous name is <code>422 MASTER_REFERENCE_AMBIGUOUS</code>; inactive/unverifiable status is <code>400 INVALID_PARAMETER</code>. Invalid object shape/unknown keys are refused by strict JSON and reference validation. A refusal is not a successful create. Existing <code>502 BUSY_WRITE_UNVERIFIED</code> means a voucher was saved but independent proof differs (including possible salesman fields); <code>504 BUSY_WRITE_UNCERTAIN</code> may have saved. Preserve any known ID, reconcile BUSY and the write job before a new attempt. Never blind-retry or use a fresh reference to mask uncertainty. These examples are source-backed and synthetic, not installed-service or cloud acceptance.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Installed public v0.0.30 predates this merged source; these are documentation examples only. Do not Send until a newer candidate with this source is installed and the target BUSY series is verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 150,\n      \"description\": [\n        \"Postman test return\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\",\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 150,\n      \"description\": [\n        \"Postman test return\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\",\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","sales-return-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"1ee72dae-847c-127a-705e-51158d9d04ee","name":"200 – return against its invoice, bill reduced (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 150, \"description\": [\"Postman test return\"] }\n  ],\n  \"narration\": \"Postman test sales return (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-return-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalInvoice`, `adjustment`, `narration` · operation `busy.sales-returns.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). The series must number automatically (`422 SALES_RETURN_SERIES_UNSUPPORTED`).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.sales-returns.create` (`POST /api/v1/sales-return-create`) creates one BUSY **sales return (credit note)** through BUSY's own COM component on this PC: the reverse of a sale — the customer is credited, the sales and GST accounts debited, the goods come back into `materialCenter`. **Create only**: it never changes, cancels or deletes a return or an invoice. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15; installed service-account acceptance **passed** 2026-10-15 (COMP0002 / 2026, returns 110-113 and nine refusals that wrote nothing; contract section 9); owner acceptance for customers is separate. **Through the cloud: not available** — Windows relays it with the write rules (same organization token), but the AI Zeny cloud has no `/v1/sales-return-create` route yet (it will be added together with the receipt route); see `docs/integration/Cloud-Sales-Return-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the return from the series. Your `returnReference` (1-60) is stored in the first narration and must be unique among the company's sales returns of the year (BUSY's own included); `narration` goes to the second narration. `lines` (1-100): `item`, `quantity` (main unit, **at most 2 decimals**), `rate`, optional `discountPercent`, `mrp`, `description`; AI Zeny calculates GST as for a sales invoice (tax-exclusive item-wise sale types; tracked items refused).\n- `originalInvoice` (optional): `{\"voucherId\": n}` or `{\"number\": \"…\"}` — the customer's own non-cancelled sales invoice of the year, dated on or before the return, same local/central kind. Its real number and date are recorded. No item may come back beyond what it sold less earlier non-cancelled returns naming it (BUSY's own included).\n- `adjustment` (optional, default on account): `{\"type\": \"onAccount\"}`, `{\"type\": \"againstOriginalInvoice\", \"amount\"?: n}` (reduces the invoice's own bill, never below zero; default the smaller of the return amount and the outstanding amount) or `{\"type\": \"newReference\", \"number\": \"…\", \"dueDate\"?: \"YYYY-MM-DD\", \"amount\"?: n}` (a credit reference with a number new to the customer). The rest stays on account (`data.unallocatedAmount`). Adjustments only for a customer BUSY keeps bill by bill.\n- AI Zeny compares BUSY's read-back, the saved rows (reversed signs, stock back in) and the adjusted bill before answering. Receipts and sales returns share one lock on the PC.\n\n**Refused before BUSY (BUSY's own import would accept them):** an unknown master name (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), another customer's invoice (`422 SALES_RETURN_ORIGINAL_MISMATCH`), a cancelled one (`422 SALES_RETURN_ORIGINAL_CANCELLED`), a number shared by several of the customer's invoices (`422 SALES_RETURN_ORIGINAL_AMBIGUOUS` — send `voucherId`), more than was sold less earlier returns (`422 SALES_RETURN_QUANTITY_EXCEEDS_SALE`, `field` `lines[i].quantity` or `lines[i].item`), history that cannot be tied to the invoice (`422 SALES_RETURN_HISTORY_AMBIGUOUS`), over-settlement (`422 SALES_RETURN_BILL_OVERSETTLED`), a settled or missing bill (`422 SALES_RETURN_BILL_NOT_FOUND`), a reused reference number (`409 SALES_RETURN_NEW_REFERENCE_TAKEN`), a tracked item (`422 SALES_RETURN_ITEM_UNSUPPORTED`), 3 decimals (`400`). A return number, billing block, amounts or XML are never accepted (`400`).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `returnReference` (current value) before each send — for example `AZPM-SR-0NN`. The request is skipped without one. Do not reuse `AZPOC-SR-…` or `AZSVC-SR-…` (earlier test records, including the acceptance's invoices 106-108 and returns 110-113).\n- The example body is a **standalone on-account** return (no original invoice, no adjustment), so it never depends on an invoice's remaining quantity or bill. To link an invoice, add `originalInvoice` with a fresh test invoice of the same customer (never a PoC or acceptance invoice).\n- Nothing is deleted automatically: a created test return stays in BUSY (and moves stock back in).\n- **Never retry blindly.** Sending the same `returnReference` again is refused (`409 SALES_RETURN_REFERENCE_TAKEN`, `details.returnId`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `returnId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or the adjusted bill differ (`details.returnId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs, receipts, invoices, orders and master writes), up to 2 minutes: give the request a long timeout. Body up to 128 KiB.\n\n**Sets:** `returnId` on success (usable as `voucherId` with `voucherType` `salesReturn` in the Voucher PDF request). Public guide: `docs/public/api/sales-return-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. Public guide: `docs/public/api/line-descriptions.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"returnId\": 8830,\n    \"returnNumber\": \"7\",\n    \"returnReference\": \"WEB-RET-40211\",\n    \"date\": \"2026-10-15\",\n    \"voucherSeries\": { \"code\": 252, \"name\": \"Main\" },\n    \"customer\": { \"code\": 7001, \"name\": \"Synthetic Traders\" },\n    \"saleType\": { \"code\": 9311, \"name\": \"Local-ItemWise\" },\n    \"taxation\": \"local\",\n    \"materialCenter\": { \"code\": 9501, \"name\": \"Main Store\" },\n    \"originalInvoice\": { \"voucherId\": 8790, \"number\": \"INV-21\", \"date\": \"2026-10-02\" },\n    \"lines\": [\n      { \"lineNumber\": 1, \"item\": { \"code\": 9401, \"name\": \"Synthetic Item\" }, \"unit\": \"Pcs.\", \"quantity\": 2, \"rate\": 450, \"discountPercent\": 0, \"netRate\": 450, \"taxableAmount\": 900, \"cgst\": 81, \"sgst\": 81, \"igst\": 0, \"taxAmount\": 162, \"amount\": 1062, \"mrp\": 500, \"description\": [\"Damaged in transit\"] }\n    ],\n    \"totals\": { \"quantity\": 2, \"taxableAmount\": 900, \"cgst\": 81, \"sgst\": 81, \"igst\": 0, \"taxAmount\": 162, \"amount\": 1062 },\n    \"adjustment\": { \"type\": \"againstOriginalInvoice\", \"number\": \"INV-21\", \"amount\": 1062, \"dueDate\": \"2026-11-01\", \"outstandingBefore\": 2124, \"outstandingAfter\": 1062 },\n    \"unallocatedAmount\": 0,\n    \"narration\": \"Synthetic return from the web shop\",\n    \"ledger\": [\n      { \"account\": { \"code\": 7001, \"name\": \"Synthetic Traders\" }, \"debit\": 0, \"credit\": 1062 },\n      { \"account\": { \"code\": 9201, \"name\": \"Synthetic Sales\" }, \"debit\": 900, \"credit\": 0 },\n      { \"account\": { \"code\": 9211, \"name\": \"Synthetic CGST\" }, \"debit\": 81, \"credit\": 0 },\n      { \"account\": { \"code\": 9212, \"name\": \"Synthetic SGST\" }, \"debit\": 81, \"credit\": 0 }\n    ]\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-returns.create\",\n    \"requestId\": \"8f3c2a71d0b94e6e9a1c5d7b2e4f6a80\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 1,\n    \"verification\": [\"busyReadBack\", \"savedRows\"],\n    \"elapsedMs\": 2480,\n    \"executedAt\": \"2026-10-15T09:30:00+00:00\"\n  }\n}"},{"id":"9221bc3b-0601-2ad9-eb6d-68012212060e","name":"409 – SALES_RETURN_REFERENCE_TAKEN (retry after a saved return, synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 150, \"description\": [\"Postman test return\"] }\n  ],\n  \"narration\": \"Postman test sales return (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-return-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalInvoice`, `adjustment`, `narration` · operation `busy.sales-returns.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). The series must number automatically (`422 SALES_RETURN_SERIES_UNSUPPORTED`).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.sales-returns.create` (`POST /api/v1/sales-return-create`) creates one BUSY **sales return (credit note)** through BUSY's own COM component on this PC: the reverse of a sale — the customer is credited, the sales and GST accounts debited, the goods come back into `materialCenter`. **Create only**: it never changes, cancels or deletes a return or an invoice. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15; installed service-account acceptance **passed** 2026-10-15 (COMP0002 / 2026, returns 110-113 and nine refusals that wrote nothing; contract section 9); owner acceptance for customers is separate. **Through the cloud: not available** — Windows relays it with the write rules (same organization token), but the AI Zeny cloud has no `/v1/sales-return-create` route yet (it will be added together with the receipt route); see `docs/integration/Cloud-Sales-Return-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the return from the series. Your `returnReference` (1-60) is stored in the first narration and must be unique among the company's sales returns of the year (BUSY's own included); `narration` goes to the second narration. `lines` (1-100): `item`, `quantity` (main unit, **at most 2 decimals**), `rate`, optional `discountPercent`, `mrp`, `description`; AI Zeny calculates GST as for a sales invoice (tax-exclusive item-wise sale types; tracked items refused).\n- `originalInvoice` (optional): `{\"voucherId\": n}` or `{\"number\": \"…\"}` — the customer's own non-cancelled sales invoice of the year, dated on or before the return, same local/central kind. Its real number and date are recorded. No item may come back beyond what it sold less earlier non-cancelled returns naming it (BUSY's own included).\n- `adjustment` (optional, default on account): `{\"type\": \"onAccount\"}`, `{\"type\": \"againstOriginalInvoice\", \"amount\"?: n}` (reduces the invoice's own bill, never below zero; default the smaller of the return amount and the outstanding amount) or `{\"type\": \"newReference\", \"number\": \"…\", \"dueDate\"?: \"YYYY-MM-DD\", \"amount\"?: n}` (a credit reference with a number new to the customer). The rest stays on account (`data.unallocatedAmount`). Adjustments only for a customer BUSY keeps bill by bill.\n- AI Zeny compares BUSY's read-back, the saved rows (reversed signs, stock back in) and the adjusted bill before answering. Receipts and sales returns share one lock on the PC.\n\n**Refused before BUSY (BUSY's own import would accept them):** an unknown master name (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), another customer's invoice (`422 SALES_RETURN_ORIGINAL_MISMATCH`), a cancelled one (`422 SALES_RETURN_ORIGINAL_CANCELLED`), a number shared by several of the customer's invoices (`422 SALES_RETURN_ORIGINAL_AMBIGUOUS` — send `voucherId`), more than was sold less earlier returns (`422 SALES_RETURN_QUANTITY_EXCEEDS_SALE`, `field` `lines[i].quantity` or `lines[i].item`), history that cannot be tied to the invoice (`422 SALES_RETURN_HISTORY_AMBIGUOUS`), over-settlement (`422 SALES_RETURN_BILL_OVERSETTLED`), a settled or missing bill (`422 SALES_RETURN_BILL_NOT_FOUND`), a reused reference number (`409 SALES_RETURN_NEW_REFERENCE_TAKEN`), a tracked item (`422 SALES_RETURN_ITEM_UNSUPPORTED`), 3 decimals (`400`). A return number, billing block, amounts or XML are never accepted (`400`).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `returnReference` (current value) before each send — for example `AZPM-SR-0NN`. The request is skipped without one. Do not reuse `AZPOC-SR-…` or `AZSVC-SR-…` (earlier test records, including the acceptance's invoices 106-108 and returns 110-113).\n- The example body is a **standalone on-account** return (no original invoice, no adjustment), so it never depends on an invoice's remaining quantity or bill. To link an invoice, add `originalInvoice` with a fresh test invoice of the same customer (never a PoC or acceptance invoice).\n- Nothing is deleted automatically: a created test return stays in BUSY (and moves stock back in).\n- **Never retry blindly.** Sending the same `returnReference` again is refused (`409 SALES_RETURN_REFERENCE_TAKEN`, `details.returnId`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `returnId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or the adjusted bill differ (`details.returnId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs, receipts, invoices, orders and master writes), up to 2 minutes: give the request a long timeout. Body up to 128 KiB.\n\n**Sets:** `returnId` on success (usable as `voucherId` with `voucherType` `salesReturn` in the Voucher PDF request). Public guide: `docs/public/api/sales-return-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. Public guide: `docs/public/api/line-descriptions.md`."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SALES_RETURN_REFERENCE_TAKEN\",\n      \"message\": \"A sales return of this company and financial year already holds this returnReference. A create never changes an existing return; if your earlier call saved it, metadata.error.details.returnId names it.\",\n      \"field\": \"returnReference\",\n      \"details\": { \"returnId\": 8830 }\n    },\n    \"requestId\": \"2b7d9e0c4a6f41d8b3e5c7a9f1d2e4b6\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"4989e0ea-99d9-1ac4-7043-7e25cc62fdac","name":"422 – SALES_RETURN_QUANTITY_EXCEEDS_SALE (more than sold less earlier returns, synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 150, \"description\": [\"Postman test return\"] }\n  ],\n  \"narration\": \"Postman test sales return (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-return-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalInvoice`, `adjustment`, `narration` · operation `busy.sales-returns.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). The series must number automatically (`422 SALES_RETURN_SERIES_UNSUPPORTED`).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.sales-returns.create` (`POST /api/v1/sales-return-create`) creates one BUSY **sales return (credit note)** through BUSY's own COM component on this PC: the reverse of a sale — the customer is credited, the sales and GST accounts debited, the goods come back into `materialCenter`. **Create only**: it never changes, cancels or deletes a return or an invoice. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15; installed service-account acceptance **passed** 2026-10-15 (COMP0002 / 2026, returns 110-113 and nine refusals that wrote nothing; contract section 9); owner acceptance for customers is separate. **Through the cloud: not available** — Windows relays it with the write rules (same organization token), but the AI Zeny cloud has no `/v1/sales-return-create` route yet (it will be added together with the receipt route); see `docs/integration/Cloud-Sales-Return-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the return from the series. Your `returnReference` (1-60) is stored in the first narration and must be unique among the company's sales returns of the year (BUSY's own included); `narration` goes to the second narration. `lines` (1-100): `item`, `quantity` (main unit, **at most 2 decimals**), `rate`, optional `discountPercent`, `mrp`, `description`; AI Zeny calculates GST as for a sales invoice (tax-exclusive item-wise sale types; tracked items refused).\n- `originalInvoice` (optional): `{\"voucherId\": n}` or `{\"number\": \"…\"}` — the customer's own non-cancelled sales invoice of the year, dated on or before the return, same local/central kind. Its real number and date are recorded. No item may come back beyond what it sold less earlier non-cancelled returns naming it (BUSY's own included).\n- `adjustment` (optional, default on account): `{\"type\": \"onAccount\"}`, `{\"type\": \"againstOriginalInvoice\", \"amount\"?: n}` (reduces the invoice's own bill, never below zero; default the smaller of the return amount and the outstanding amount) or `{\"type\": \"newReference\", \"number\": \"…\", \"dueDate\"?: \"YYYY-MM-DD\", \"amount\"?: n}` (a credit reference with a number new to the customer). The rest stays on account (`data.unallocatedAmount`). Adjustments only for a customer BUSY keeps bill by bill.\n- AI Zeny compares BUSY's read-back, the saved rows (reversed signs, stock back in) and the adjusted bill before answering. Receipts and sales returns share one lock on the PC.\n\n**Refused before BUSY (BUSY's own import would accept them):** an unknown master name (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), another customer's invoice (`422 SALES_RETURN_ORIGINAL_MISMATCH`), a cancelled one (`422 SALES_RETURN_ORIGINAL_CANCELLED`), a number shared by several of the customer's invoices (`422 SALES_RETURN_ORIGINAL_AMBIGUOUS` — send `voucherId`), more than was sold less earlier returns (`422 SALES_RETURN_QUANTITY_EXCEEDS_SALE`, `field` `lines[i].quantity` or `lines[i].item`), history that cannot be tied to the invoice (`422 SALES_RETURN_HISTORY_AMBIGUOUS`), over-settlement (`422 SALES_RETURN_BILL_OVERSETTLED`), a settled or missing bill (`422 SALES_RETURN_BILL_NOT_FOUND`), a reused reference number (`409 SALES_RETURN_NEW_REFERENCE_TAKEN`), a tracked item (`422 SALES_RETURN_ITEM_UNSUPPORTED`), 3 decimals (`400`). A return number, billing block, amounts or XML are never accepted (`400`).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `returnReference` (current value) before each send — for example `AZPM-SR-0NN`. The request is skipped without one. Do not reuse `AZPOC-SR-…` or `AZSVC-SR-…` (earlier test records, including the acceptance's invoices 106-108 and returns 110-113).\n- The example body is a **standalone on-account** return (no original invoice, no adjustment), so it never depends on an invoice's remaining quantity or bill. To link an invoice, add `originalInvoice` with a fresh test invoice of the same customer (never a PoC or acceptance invoice).\n- Nothing is deleted automatically: a created test return stays in BUSY (and moves stock back in).\n- **Never retry blindly.** Sending the same `returnReference` again is refused (`409 SALES_RETURN_REFERENCE_TAKEN`, `details.returnId`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `returnId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or the adjusted bill differ (`details.returnId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs, receipts, invoices, orders and master writes), up to 2 minutes: give the request a long timeout. Body up to 128 KiB.\n\n**Sets:** `returnId` on success (usable as `voucherId` with `voucherType` `salesReturn` in the Voucher PDF request). Public guide: `docs/public/api/sales-return-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. Public guide: `docs/public/api/line-descriptions.md`."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SALES_RETURN_QUANTITY_EXCEEDS_SALE\",\n      \"message\": \"The quantity is more than the original invoice sold of this item less its earlier sales returns in BUSY. Return at most the quantity still returnable.\",\n      \"field\": \"lines[0].quantity\"\n    },\n    \"requestId\": \"c4e6a8b0d2f4416a8c0e2a4c6e8a0b2d\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"5060fa6a-c36a-2684-f8aa-62f68631da18","name":"422 – SALES_RETURN_BILL_OVERSETTLED (adjustment above the bill's outstanding, synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 150, \"description\": [\"Postman test return\"] }\n  ],\n  \"narration\": \"Postman test sales return (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-return-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalInvoice`, `adjustment`, `narration` · operation `busy.sales-returns.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). The series must number automatically (`422 SALES_RETURN_SERIES_UNSUPPORTED`).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.sales-returns.create` (`POST /api/v1/sales-return-create`) creates one BUSY **sales return (credit note)** through BUSY's own COM component on this PC: the reverse of a sale — the customer is credited, the sales and GST accounts debited, the goods come back into `materialCenter`. **Create only**: it never changes, cancels or deletes a return or an invoice. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15; installed service-account acceptance **passed** 2026-10-15 (COMP0002 / 2026, returns 110-113 and nine refusals that wrote nothing; contract section 9); owner acceptance for customers is separate. **Through the cloud: not available** — Windows relays it with the write rules (same organization token), but the AI Zeny cloud has no `/v1/sales-return-create` route yet (it will be added together with the receipt route); see `docs/integration/Cloud-Sales-Return-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the return from the series. Your `returnReference` (1-60) is stored in the first narration and must be unique among the company's sales returns of the year (BUSY's own included); `narration` goes to the second narration. `lines` (1-100): `item`, `quantity` (main unit, **at most 2 decimals**), `rate`, optional `discountPercent`, `mrp`, `description`; AI Zeny calculates GST as for a sales invoice (tax-exclusive item-wise sale types; tracked items refused).\n- `originalInvoice` (optional): `{\"voucherId\": n}` or `{\"number\": \"…\"}` — the customer's own non-cancelled sales invoice of the year, dated on or before the return, same local/central kind. Its real number and date are recorded. No item may come back beyond what it sold less earlier non-cancelled returns naming it (BUSY's own included).\n- `adjustment` (optional, default on account): `{\"type\": \"onAccount\"}`, `{\"type\": \"againstOriginalInvoice\", \"amount\"?: n}` (reduces the invoice's own bill, never below zero; default the smaller of the return amount and the outstanding amount) or `{\"type\": \"newReference\", \"number\": \"…\", \"dueDate\"?: \"YYYY-MM-DD\", \"amount\"?: n}` (a credit reference with a number new to the customer). The rest stays on account (`data.unallocatedAmount`). Adjustments only for a customer BUSY keeps bill by bill.\n- AI Zeny compares BUSY's read-back, the saved rows (reversed signs, stock back in) and the adjusted bill before answering. Receipts and sales returns share one lock on the PC.\n\n**Refused before BUSY (BUSY's own import would accept them):** an unknown master name (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), another customer's invoice (`422 SALES_RETURN_ORIGINAL_MISMATCH`), a cancelled one (`422 SALES_RETURN_ORIGINAL_CANCELLED`), a number shared by several of the customer's invoices (`422 SALES_RETURN_ORIGINAL_AMBIGUOUS` — send `voucherId`), more than was sold less earlier returns (`422 SALES_RETURN_QUANTITY_EXCEEDS_SALE`, `field` `lines[i].quantity` or `lines[i].item`), history that cannot be tied to the invoice (`422 SALES_RETURN_HISTORY_AMBIGUOUS`), over-settlement (`422 SALES_RETURN_BILL_OVERSETTLED`), a settled or missing bill (`422 SALES_RETURN_BILL_NOT_FOUND`), a reused reference number (`409 SALES_RETURN_NEW_REFERENCE_TAKEN`), a tracked item (`422 SALES_RETURN_ITEM_UNSUPPORTED`), 3 decimals (`400`). A return number, billing block, amounts or XML are never accepted (`400`).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `returnReference` (current value) before each send — for example `AZPM-SR-0NN`. The request is skipped without one. Do not reuse `AZPOC-SR-…` or `AZSVC-SR-…` (earlier test records, including the acceptance's invoices 106-108 and returns 110-113).\n- The example body is a **standalone on-account** return (no original invoice, no adjustment), so it never depends on an invoice's remaining quantity or bill. To link an invoice, add `originalInvoice` with a fresh test invoice of the same customer (never a PoC or acceptance invoice).\n- Nothing is deleted automatically: a created test return stays in BUSY (and moves stock back in).\n- **Never retry blindly.** Sending the same `returnReference` again is refused (`409 SALES_RETURN_REFERENCE_TAKEN`, `details.returnId`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `returnId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or the adjusted bill differ (`details.returnId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs, receipts, invoices, orders and master writes), up to 2 minutes: give the request a long timeout. Body up to 128 KiB.\n\n**Sets:** `returnId` on success (usable as `voucherId` with `voucherType` `salesReturn` in the Voucher PDF request). Public guide: `docs/public/api/sales-return-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. Public guide: `docs/public/api/line-descriptions.md`."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SALES_RETURN_BILL_OVERSETTLED\",\n      \"message\": \"The adjustment is larger than the original invoice's outstanding amount in BUSY. Adjust at most the outstanding amount; the rest stays on account.\",\n      \"field\": \"adjustment.amount\"\n    },\n    \"requestId\": \"5a7c9e1b3d5f47a9b1c3e5a7c9e1b3d5\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"fad88b6c-435c-1e19-d0ff-c76e5279e6cf","name":"504 – BUSY_WRITE_UNCERTAIN (reconciled: found, synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 150, \"description\": [\"Postman test return\"] }\n  ],\n  \"narration\": \"Postman test sales return (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create","description":"**Local** · `POST {{baseUrl}}/api/v1/sales-return-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalInvoice`, `adjustment`, `narration` · operation `busy.sales-returns.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq). The series must number automatically (`422 SALES_RETURN_SERIES_UNSUPPORTED`).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.sales-returns.create` (`POST /api/v1/sales-return-create`) creates one BUSY **sales return (credit note)** through BUSY's own COM component on this PC: the reverse of a sale — the customer is credited, the sales and GST accounts debited, the goods come back into `materialCenter`. **Create only**: it never changes, cancels or deletes a return or an invoice. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15; installed service-account acceptance **passed** 2026-10-15 (COMP0002 / 2026, returns 110-113 and nine refusals that wrote nothing; contract section 9); owner acceptance for customers is separate. **Through the cloud: not available** — Windows relays it with the write rules (same organization token), but the AI Zeny cloud has no `/v1/sales-return-create` route yet (it will be added together with the receipt route); see `docs/integration/Cloud-Sales-Return-Relay-Handoff.md`.\n\n**How it works.** BUSY numbers the return from the series. Your `returnReference` (1-60) is stored in the first narration and must be unique among the company's sales returns of the year (BUSY's own included); `narration` goes to the second narration. `lines` (1-100): `item`, `quantity` (main unit, **at most 2 decimals**), `rate`, optional `discountPercent`, `mrp`, `description`; AI Zeny calculates GST as for a sales invoice (tax-exclusive item-wise sale types; tracked items refused).\n- `originalInvoice` (optional): `{\"voucherId\": n}` or `{\"number\": \"…\"}` — the customer's own non-cancelled sales invoice of the year, dated on or before the return, same local/central kind. Its real number and date are recorded. No item may come back beyond what it sold less earlier non-cancelled returns naming it (BUSY's own included).\n- `adjustment` (optional, default on account): `{\"type\": \"onAccount\"}`, `{\"type\": \"againstOriginalInvoice\", \"amount\"?: n}` (reduces the invoice's own bill, never below zero; default the smaller of the return amount and the outstanding amount) or `{\"type\": \"newReference\", \"number\": \"…\", \"dueDate\"?: \"YYYY-MM-DD\", \"amount\"?: n}` (a credit reference with a number new to the customer). The rest stays on account (`data.unallocatedAmount`). Adjustments only for a customer BUSY keeps bill by bill.\n- AI Zeny compares BUSY's read-back, the saved rows (reversed signs, stock back in) and the adjusted bill before answering. Receipts and sales returns share one lock on the PC.\n\n**Refused before BUSY (BUSY's own import would accept them):** an unknown master name (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), another customer's invoice (`422 SALES_RETURN_ORIGINAL_MISMATCH`), a cancelled one (`422 SALES_RETURN_ORIGINAL_CANCELLED`), a number shared by several of the customer's invoices (`422 SALES_RETURN_ORIGINAL_AMBIGUOUS` — send `voucherId`), more than was sold less earlier returns (`422 SALES_RETURN_QUANTITY_EXCEEDS_SALE`, `field` `lines[i].quantity` or `lines[i].item`), history that cannot be tied to the invoice (`422 SALES_RETURN_HISTORY_AMBIGUOUS`), over-settlement (`422 SALES_RETURN_BILL_OVERSETTLED`), a settled or missing bill (`422 SALES_RETURN_BILL_NOT_FOUND`), a reused reference number (`409 SALES_RETURN_NEW_REFERENCE_TAKEN`), a tracked item (`422 SALES_RETURN_ITEM_UNSUPPORTED`), 3 decimals (`400`). A return number, billing block, amounts or XML are never accepted (`400`).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `returnReference` (current value) before each send — for example `AZPM-SR-0NN`. The request is skipped without one. Do not reuse `AZPOC-SR-…` or `AZSVC-SR-…` (earlier test records, including the acceptance's invoices 106-108 and returns 110-113).\n- The example body is a **standalone on-account** return (no original invoice, no adjustment), so it never depends on an invoice's remaining quantity or bill. To link an invoice, add `originalInvoice` with a fresh test invoice of the same customer (never a PoC or acceptance invoice).\n- Nothing is deleted automatically: a created test return stays in BUSY (and moves stock back in).\n- **Never retry blindly.** Sending the same `returnReference` again is refused (`409 SALES_RETURN_REFERENCE_TAKEN`, `details.returnId`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `returnId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or the adjusted bill differ (`details.returnId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs, receipts, invoices, orders and master writes), up to 2 minutes: give the request a long timeout. Body up to 128 KiB.\n\n**Sets:** `returnId` on success (usable as `voucherId` with `voucherType` `salesReturn` in the Voucher PDF request). Public guide: `docs/public/api/sales-return-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. Public guide: `docs/public/api/line-descriptions.md`."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"BUSY stopped while saving the sales return; a sales return with this returnReference exists now (metadata.error.details.returnId). Check it in BUSY; do not send it again.\",\n      \"details\": { \"returnId\": 8831, \"reconciliation\": \"found\" }\n    },\n    \"requestId\": \"e1f3a5c7b9d14e2f8a0c2e4a6c8e0a2c\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"a98c5aec-192e-7fa6-a4cf-4e6a87272150","name":"409 – GST_CONFIGURATION_CHANGED (before save)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic 5% item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0,\n        \"amount\": 13.26\n      }\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\",\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0,\n    \"amount\": 13.26\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"GST_CONFIGURATION_CHANGED\",\n      \"message\": \"BUSY's selected GST or voucher-series configuration changed while this request was being prepared. Read it again and submit a new request.\"\n    }\n  }\n}"},{"id":"711cc29c-7dc6-91e6-9753-e598d09e54d6","name":"422 – GST_AMOUNTS_INVALID (manual treatment)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic 5% item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0.05,\n        \"amount\": 13.31\n      }\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\",\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0.05,\n    \"amount\": 13.31\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"GST_AMOUNTS_INVALID\",\n      \"message\": \"Manual GST amounts conflict with the selected tax rate or local/central treatment.\"\n    }\n  }\n}"},{"id":"06da5ee3-e24a-82d8-a769-3acad6614657","name":"502 – BUSY_WRITE_UNVERIFIED (saved; reconcile)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic 5% item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0,\n        \"amount\": 13.26\n      }\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\",\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0,\n    \"amount\": 13.26\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create"},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNVERIFIED\",\n      \"message\": \"BUSY saved the voucher but read-back differs; inspect the saved reference and do not resend.\"\n    }\n  }\n}"},{"id":"5d577bc0-d1c3-1336-fed4-232226775b66","name":"400 – INVALID_PARAMETER (Manual breakdown missing)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 150,\n      \"description\": [\n        \"Postman test return\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"Manual GST breakdown is required for every line and document totals.\"\n    }\n  }\n}"},{"id":"d3b72225-098b-b0a4-461c-a0d4818eec2b","name":"422 – GST_MODE_UNSUPPORTED (Sales Return linked original)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstInclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 150,\n      \"description\": [\n        \"Postman test return\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\",\n  \"originalInvoice\": {\n    \"voucherId\": 1\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"GST_MODE_UNSUPPORTED\",\n      \"message\": \"This new GST mode and linked/allocated/sundry combination requires separate native proof.\",\n      \"field\": \"originalInvoice\"\n    }\n  }\n}"},{"id":"4da18c00-9ec7-0d3e-fb8b-40c0340237f7","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 150,\n      \"description\": [\n        \"Postman test return\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\",\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"synthetic-queue-001"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-returns.create\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"},{"id":"15e6d202-b4b5-8d19-0869-73f1fd5de5db","name":"200 – salesman assigned (synthetic Local; code)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 150,\n      \"description\": [\n        \"Postman test return\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\",\n  \"salesman\": {\n    \"code\": 9701\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"returnId\": 8830,\n    \"returnNumber\": \"7\",\n    \"returnReference\": \"WEB-RET-40211\",\n    \"date\": \"2026-10-15\",\n    \"voucherSeries\": {\n      \"code\": 252,\n      \"name\": \"Main\"\n    },\n    \"customer\": {\n      \"code\": 7001,\n      \"name\": \"Synthetic Traders\"\n    },\n    \"saleType\": {\n      \"code\": 9311,\n      \"name\": \"Local-ItemWise\"\n    },\n    \"taxation\": \"local\",\n    \"materialCenter\": {\n      \"code\": 9501,\n      \"name\": \"Main Store\"\n    },\n    \"originalInvoice\": {\n      \"voucherId\": 8790,\n      \"number\": \"INV-21\",\n      \"date\": \"2026-10-02\"\n    },\n    \"lines\": [\n      {\n        \"lineNumber\": 1,\n        \"item\": {\n          \"code\": 9401,\n          \"name\": \"Synthetic Item\"\n        },\n        \"unit\": \"Pcs.\",\n        \"quantity\": 2,\n        \"rate\": 450,\n        \"discountPercent\": 0,\n        \"netRate\": 450,\n        \"taxableAmount\": 900,\n        \"cgst\": 81,\n        \"sgst\": 81,\n        \"igst\": 0,\n        \"taxAmount\": 162,\n        \"amount\": 1062,\n        \"mrp\": 500,\n        \"description\": [\n          \"Damaged in transit\"\n        ]\n      }\n    ],\n    \"totals\": {\n      \"quantity\": 2,\n      \"taxableAmount\": 900,\n      \"cgst\": 81,\n      \"sgst\": 81,\n      \"igst\": 0,\n      \"taxAmount\": 162,\n      \"amount\": 1062\n    },\n    \"adjustment\": {\n      \"type\": \"againstOriginalInvoice\",\n      \"number\": \"INV-21\",\n      \"amount\": 1062,\n      \"dueDate\": \"2026-11-01\",\n      \"outstandingBefore\": 2124,\n      \"outstandingAfter\": 1062\n    },\n    \"unallocatedAmount\": 0,\n    \"narration\": \"Synthetic return from the web shop\",\n    \"ledger\": [\n      {\n        \"account\": {\n          \"code\": 7001,\n          \"name\": \"Synthetic Traders\"\n        },\n        \"debit\": 0,\n        \"credit\": 1062\n      },\n      {\n        \"account\": {\n          \"code\": 9201,\n          \"name\": \"Synthetic Sales\"\n        },\n        \"debit\": 900,\n        \"credit\": 0\n      },\n      {\n        \"account\": {\n          \"code\": 9211,\n          \"name\": \"Synthetic CGST\"\n        },\n        \"debit\": 81,\n        \"credit\": 0\n      },\n      {\n        \"account\": {\n          \"code\": 9212,\n          \"name\": \"Synthetic SGST\"\n        },\n        \"debit\": 81,\n        \"credit\": 0\n      }\n    ],\n    \"salesman\": {\n      \"code\": 9701,\n      \"name\": \"Synthetic Salesman\"\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-returns.create\",\n    \"requestId\": \"8f3c2a71d0b94e6e9a1c5d7b2e4f6a80\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 1,\n    \"verification\": [\n      \"busyReadBack\",\n      \"savedRows\"\n    ],\n    \"elapsedMs\": 2480,\n    \"executedAt\": \"2026-10-15T09:30:00+00:00\"\n  }\n}"},{"id":"bc45588c-0454-4ab8-e773-61b1ef8608ed","name":"200 – salesman explicitly null (synthetic Local; native default)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 150,\n      \"description\": [\n        \"Postman test return\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\",\n  \"salesman\": null\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"returnId\": 8830,\n    \"returnNumber\": \"7\",\n    \"returnReference\": \"WEB-RET-40211\",\n    \"date\": \"2026-10-15\",\n    \"voucherSeries\": {\n      \"code\": 252,\n      \"name\": \"Main\"\n    },\n    \"customer\": {\n      \"code\": 7001,\n      \"name\": \"Synthetic Traders\"\n    },\n    \"saleType\": {\n      \"code\": 9311,\n      \"name\": \"Local-ItemWise\"\n    },\n    \"taxation\": \"local\",\n    \"materialCenter\": {\n      \"code\": 9501,\n      \"name\": \"Main Store\"\n    },\n    \"originalInvoice\": {\n      \"voucherId\": 8790,\n      \"number\": \"INV-21\",\n      \"date\": \"2026-10-02\"\n    },\n    \"lines\": [\n      {\n        \"lineNumber\": 1,\n        \"item\": {\n          \"code\": 9401,\n          \"name\": \"Synthetic Item\"\n        },\n        \"unit\": \"Pcs.\",\n        \"quantity\": 2,\n        \"rate\": 450,\n        \"discountPercent\": 0,\n        \"netRate\": 450,\n        \"taxableAmount\": 900,\n        \"cgst\": 81,\n        \"sgst\": 81,\n        \"igst\": 0,\n        \"taxAmount\": 162,\n        \"amount\": 1062,\n        \"mrp\": 500,\n        \"description\": [\n          \"Damaged in transit\"\n        ]\n      }\n    ],\n    \"totals\": {\n      \"quantity\": 2,\n      \"taxableAmount\": 900,\n      \"cgst\": 81,\n      \"sgst\": 81,\n      \"igst\": 0,\n      \"taxAmount\": 162,\n      \"amount\": 1062\n    },\n    \"adjustment\": {\n      \"type\": \"againstOriginalInvoice\",\n      \"number\": \"INV-21\",\n      \"amount\": 1062,\n      \"dueDate\": \"2026-11-01\",\n      \"outstandingBefore\": 2124,\n      \"outstandingAfter\": 1062\n    },\n    \"unallocatedAmount\": 0,\n    \"narration\": \"Synthetic return from the web shop\",\n    \"ledger\": [\n      {\n        \"account\": {\n          \"code\": 7001,\n          \"name\": \"Synthetic Traders\"\n        },\n        \"debit\": 0,\n        \"credit\": 1062\n      },\n      {\n        \"account\": {\n          \"code\": 9201,\n          \"name\": \"Synthetic Sales\"\n        },\n        \"debit\": 900,\n        \"credit\": 0\n      },\n      {\n        \"account\": {\n          \"code\": 9211,\n          \"name\": \"Synthetic CGST\"\n        },\n        \"debit\": 81,\n        \"credit\": 0\n      },\n      {\n        \"account\": {\n          \"code\": 9212,\n          \"name\": \"Synthetic SGST\"\n        },\n        \"debit\": 81,\n        \"credit\": 0\n      }\n    ]\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-returns.create\",\n    \"requestId\": \"8f3c2a71d0b94e6e9a1c5d7b2e4f6a80\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 1,\n    \"verification\": [\n      \"busyReadBack\",\n      \"savedRows\"\n    ],\n    \"elapsedMs\": 2480,\n    \"executedAt\": \"2026-10-15T09:30:00+00:00\"\n  }\n}"},{"id":"ab1f1060-23ae-f62a-fb47-d4f4b959f01b","name":"409 – SALESMAN_CONFIGURATION_UNSUPPORTED (synthetic; nothing saved)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 150,\n      \"description\": [\n        \"Postman test return\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\",\n  \"salesman\": {\n    \"code\": 9701\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SALESMAN_CONFIGURATION_UNSUPPORTED\",\n      \"message\": \"The company does not support the requested voucher-level salesman assignment.\",\n      \"field\": \"salesman\"\n    }\n  }\n}"},{"id":"2a5b8d34-c2a0-f3e6-b719-a2d050c07389","name":"409 – SALESMAN_CONFIGURATION_CHANGED (synthetic; nothing saved)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 150,\n      \"description\": [\n        \"Postman test return\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\",\n  \"salesman\": {\n    \"code\": 9701\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SALESMAN_CONFIGURATION_CHANGED\",\n      \"message\": \"The salesman or its configuration changed before save; nothing was saved.\",\n      \"field\": \"salesman\"\n    }\n  }\n}"},{"id":"c8ca7558-398e-5933-e4d8-bc2ae5a84b24","name":"422 – MASTER_REFERENCE_NOT_FOUND salesman (synthetic; nothing saved)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 150,\n      \"description\": [\n        \"Postman test return\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\",\n  \"salesman\": {\n    \"code\": 999999\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"MASTER_REFERENCE_NOT_FOUND\",\n      \"message\": \"No salesman with that code or name exists in this company and financial year.\",\n      \"field\": \"salesman\"\n    }\n  }\n}"}],"_postman_id":"38158799-3dd8-030c-c907-896163fdd269"},{"name":"⚠ BUSY purchase – create (writes to BUSY)","id":"b155cae7-f27b-aa61-d1f3-a71bb54bc1e3","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": { \"number\": \"{{purchaseReference}}\", \"date\": \"2026-10-15\" },\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PUR SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100, \"description\": [\"Postman test purchase\"] }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-create","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/purchase-create</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>⚠ Writes to BUSY</strong> (Development Local Send requires no separate confirmation)\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>purchaseReference</code>, <code>date</code>, <code>supplierInvoice</code> (<code>number</code>, <code>date</code>), <code>supplier</code>, <code>purchaseType</code>, <code>materialCenter</code>, <code>lines</code> · <strong>Optional:</strong> <code>voucherNumber</code>, <code>voucherSeries</code>, <code>billSundries</code>, <code>dueDate</code>, <code>narration</code> · operation <code>busy.purchases.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books. Run manually, one at a time.</strong> <code>busy.purchases.create</code> (<code>POST /api/v1/purchase-create</code>) creates one BUSY <strong>purchase</strong> through BUSY's own COM component on this PC: the supplier is credited with the total, the purchase and GST input accounts debited, the goods come into <code>materialCenter</code> at their cost. <strong>Create only</strong>: it never changes, cancels or deletes a purchase. <strong>SQL Server companies with a SQL login, or Access companies</strong>. Never run from scripts. <strong>Status:</strong> implemented 2026-10-15; <strong>installed service-account acceptance passed 2026-10-15</strong> (COMP0002 / 2026: five purchases saved and verified, ten refusals wrote nothing); owner acceptance for customers is separate. <strong>Through the cloud: not available</strong> — the PC is relay-ready (same organization token, write rules), but the AI Zeny cloud has no purchase route and none is part of this work.</p>\n<p><strong>How it works.</strong></p>\n<ul>\n<li><strong>Three numbers, kept apart:</strong> your <code>purchaseReference</code> (1-60, first narration, unique among the company's purchases of the year — the retry key); the supplier's own invoice <code>supplierInvoice.number</code> (1-25, unique among that supplier's non-cancelled purchases of the year) and <code>date</code>; BUSY's <code>voucherNumber</code> (1-25, default the supplier invoice number, never empty), which must be new in the series. Only a purchase series with <strong>manual</strong> numbering is accepted.</li>\n<li><code>lines</code> (1-100): <code>item</code>, <code>quantity</code> (main unit, <strong>at most 2 decimals</strong>), <code>rate</code>, optional <code>discountPercent</code> (the rate after discount must have at most 2 decimals — never rounded for you), <code>mrp</code>, <code>description</code>, and <code>parameters</code> (required for a parameter-wise item, adding up exactly to the line; refused for any other item). GST is calculated as for a sales invoice (matching item-wise purchase types).</li>\n<li><strong>Parameter-wise items</strong> are offered only when the company's parameter setup in BUSY is one parameter (free text or a list of values): each value must fit the parameter's width and, for a list, be one of its values exactly as BUSY shows them (on COMP0002: <code>Size</code>, <code>Color</code>). Any other setup, or none, is <code>422 PURCHASE_ITEM_UNSUPPORTED</code> — an item without parameter history is never assumed to have one field.</li>\n<li><code>billSundries</code> (optional, at most 10): one percentage discount (on the lines' amounts with GST; amount half away from zero; spread over the line costs half to even, the first line taking the remainder, as BUSY's window does), fixed charges, one round-off ≤ 0.99 — only bill sundries set up like BUSY's own Discount, Freight &amp; Forwarding Charges and Rounded Off (+)/(-).</li>\n<li>For a supplier BUSY keeps bill by bill, one payable named by the supplier invoice number (optional <code>dueDate</code>; default the supplier's purchase credit days).</li>\n<li>No \"purpose of purchase\" is sent (a state-VAT field; that BUSY's own default suits every setup is not proven).</li>\n<li>AI Zeny compares BUSY's read-back and the saved rows (ledger, costs, sundries, payable, parameter rows, GST summary) before answering. Purchases, receipts and sales returns share one lock on the PC.</li>\n</ul>\n<p><strong>Refused before BUSY:</strong> an unknown master (<code>422 MASTER_REFERENCE_NOT_FOUND</code>; BUSY would create it), a reference already held (<code>409 PURCHASE_REFERENCE_TAKEN</code>, <code>details.purchaseId</code>), the supplier's invoice already entered (<code>409 PURCHASE_SUPPLIER_INVOICE_TAKEN</code>, <code>details.purchaseId</code>), a voucher number in the series (<code>409 PURCHASE_NUMBER_TAKEN</code>), a payable name the supplier already uses (<code>409 PURCHASE_BILL_REFERENCE_TAKEN</code>), an automatic series (<code>422 PURCHASE_SERIES_UNSUPPORTED</code>), a cash/bank supplier (<code>422 PURCHASE_SUPPLIER_UNSUPPORTED</code>), other purchase types or tax categories (<code>422 PURCHASE_TYPE_UNSUPPORTED</code> / <code>PURCHASE_TAX_UNSUPPORTED</code>), serial, batch, multi-parameter, unproven-parameter-setup or non-1-conversion items (<code>422 PURCHASE_ITEM_UNSUPPORTED</code>), parameter rows wrong, too long or not in the setup's list (<code>422 PURCHASE_PARAMETERS_INVALID</code>), other bill sundries or combinations (<code>422 PURCHASE_BILL_SUNDRY_UNSUPPORTED</code>), a <code>dueDate</code> for a supplier not kept bill by bill (<code>422 PURCHASE_DUE_DATE_UNSUPPORTED</code>), 3 decimals (<code>400</code>). A purpose code, billing block or XML is never accepted; Manual monetary amounts follow the GST billing-mode contract (<code>400</code>).</p>\n<p><strong>Safe test guidance</strong></p>\n<ul>\n<li>Select a development-test <code>companyCode</code> (<code>COMP0002</code> / FY 2026 in this environment; use <code>COMP0001</code> for Access tests). With <code>autoVoucherReferences=yes</code>, each Local Send generates and stores a fresh 25-character synthetic <code>purchaseReference</code>. Set that switch to <code>no</code> to supply your own unique reference. The reference is also the supplier invoice number and default voucher number. Do not reuse <code>AZPOC-PUR-…</code> or <code>AZSVC-PUR-…</code> (PoC and acceptance records, including purchases 114-150).</li>\n<li>The example body is one local line for the PoC's test supplier with no bill sundries; it creates a payable (the supplier is kept bill by bill).</li>\n<li>Nothing is deleted automatically: a created test purchase stays in BUSY (and moves stock in).</li>\n<li><strong>Never retry blindly.</strong> Automatic references change on each Send, so another Send can create another voucher; reconcile an uncertain result first. Sending the same <code>purchaseReference</code> again is refused (<code>409 PURCHASE_REFERENCE_TAKEN</code>) if the first send saved. After <code>504 BUSY_WRITE_UNCERTAIN</code>, read <code>metadata.error.details.reconciliation</code> (<code>found</code> + <code>purchaseId</code>, <code>notFound</code>, <code>notChecked</code>) and check BUSY first.</li>\n<li><code>502 BUSY_WRITE_UNVERIFIED</code> means BUSY <strong>did</strong> save but its read-back, saved rows or payable differ (<code>details.purchaseId</code>, <code>details.mismatchedFields</code>).</li>\n<li>One BUSY job at a time on the PC (shared with voucher PDFs and the other writes), up to 2 minutes: give the request a long timeout. Body up to 128 KiB.</li>\n</ul>\n<p><strong>Sets:</strong> <code>purchaseId</code> on success (usable as <code>voucherId</code> with <code>voucherType</code> <code>purchaseInvoice</code> in the Voucher PDF request). Public guide: <code>docs/public/api/purchase-create.md</code>.</p>\n<p><strong>Line descriptions (owner acceptance 2026-10-19; <code>docs/features/BUSY-Voucher-Line-Descriptions.md</code>):</strong> <code>lines[].description</code> is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; <code>\"\"</code> or <code>null</code> keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise <code>422 BUSY_SETTING_REQUIRED</code> (<code>lines[i].description</code>) or <code>422 DESCRIPTION_LINE_NOT_ALLOWED</code> (<code>lines[i].description[n]</code>), nothing saved. SQL Server companies take Latin-1 characters only (<code>400</code>, before BUSY); Access companies any text. The answer's lines carry <code>description</code> as saved. Public guide: <code>docs/public/api/line-descriptions.md</code>.</p>\n<p><strong>GST billing modes (bounded internal 0.0.15 candidate accepted 2026-10-20 on Access and SQL Server; 0.0.16 release smoke was narrower):</strong> Optional <code>taxCalculation</code> is <code>auto</code> (default) or <code>manual</code>; optional <code>pricingMode</code> is <code>gstExclusive</code> (default) or <code>gstInclusive</code>. JSON <code>null</code> selects each default. One pricing mode applies to every line. <code>rate</code> is the unit price before discount, GST included only for <code>gstInclusive</code>; choose a native item-wise sale/purchase type whose inclusive setting matches. Tax rates come from each selected item's configured category for this company/year; local uses CGST+SGST, central uses IGST. Mixed-rate lines are allowed. Auto computes money using decimal arithmetic. Manual requires every line's <code>amounts</code> and document <code>totals</code>, each with <code>taxableAmount</code>, <code>cgst</code>, <code>sgst</code>, <code>igst</code>, <code>amount</code> (JSON numbers, max two decimals). <code>amount</code> equals taxable plus components; totals equal exact line sums. Local IGST and central CGST/SGST must be zero; submitted values must satisfy the narrow configured-rate and one-paisa bounds in <code>docs/features/BUSY-GST-Billing-Modes-Create-API.md</code>. No balancing charge or silent replacement. Returns submit positive amounts; BUSY posts reversal signs. Malformed JSON or unknown fields: <code>400 BAD_REQUEST</code>; missing or inconsistent Manual amounts: <code>400 INVALID_PARAMETER</code>; invalid configured-rate/treatment: <code>422 GST_AMOUNTS_INVALID</code>; unproven new-mode combination: <code>422 GST_MODE_UNSUPPORTED</code>; changed configuration before save: <code>409 GST_CONFIGURATION_CHANGED</code>. If saved read-back mismatches: <code>502 BUSY_WRITE_UNVERIFIED</code> means saved and requires reconciliation, never automatic retry. Linked returns and bill allocations, manual Purchase sundry discounts, and zero/exempt/nil treatment are not proven for new modes; existing Auto/exclusive supported flows remain. Cloud routes are not claimed deployed.</p>\n<p><strong>Mode payload examples</strong> (fragments; retain the route's company/year/date/reference/party/series/centre fields and use a matching configured native type):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\"taxCalculation\":\"auto\",\"pricingMode\":\"gstExclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 5% item\"},\"quantity\":1.25,\"rate\":10.10}]}\n{\"taxCalculation\":\"auto\",\"pricingMode\":\"gstInclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 18% item\"},\"quantity\":0.5,\"rate\":25.00}]}\n{\"taxCalculation\":\"manual\",\"pricingMode\":\"gstExclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 5% item\"},\"quantity\":1.25,\"rate\":10.10,\"amounts\":{\"taxableAmount\":12.62,\"cgst\":0.32,\"sgst\":0.32,\"igst\":0,\"amount\":13.26}}],\"totals\":{\"taxableAmount\":12.62,\"cgst\":0.32,\"sgst\":0.32,\"igst\":0,\"amount\":13.26}}\n{\"taxCalculation\":\"manual\",\"pricingMode\":\"gstInclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 18% item\"},\"quantity\":0.5,\"rate\":25.00,\"amounts\":{\"taxableAmount\":10.59,\"cgst\":0.96,\"sgst\":0.95,\"igst\":0,\"amount\":12.50}}],\"totals\":{\"taxableAmount\":10.59,\"cgst\":0.96,\"sgst\":0.95,\"igst\":0,\"amount\":12.50}}\n</code></pre>\n<p><strong>Mixed-rate Manual inclusive example:</strong> one 5% line may use a different configured tax category from an 18% line; sum every five amounts members exactly into totals. For central treatment replace both local components with IGST under the selected central native type. The one-paisa 18% example above shows the corrected CGST/SGST mapping. These are synthetic fragments, not live execution records.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n<h2 id=\"full-synthetic-gst-request-examples-local-only\">FULL synthetic GST request examples (Local only)</h2>\n<p>The raw Body tab above stays the minimal Auto/exclusive request. These separate complete bodies assume existing synthetic 5%/18% item tax categories, a matching item-wise native type, series, party and centre in the selected company/FY; replace fixture names and use a fresh reference before any send. <code>Local-TaxIncl.</code> must be configured with inclusive B13. Every line shares the voucher pricing mode. The amounts below are local CGST/SGST examples; for interstate treatment select the matching Central type and supply IGST instead. Return amounts remain positive in the request and BUSY reverses the postings. Do not infer Cloud Relay deployment from these Windows Local examples.</p>\n<p><strong>Auto + inclusive (synthetic FULL body):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstInclusive\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": {\n    \"number\": \"{{purchaseReference}}\",\n    \"date\": \"2026-10-15\"\n  },\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-TaxIncl.\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic GST 18% Item\"\n      },\n      \"quantity\": 0.5,\n      \"rate\": 25\n    }\n  ],\n  \"narration\": \"Postman test purchase\"\n}\n</code></pre>\n<p><strong>Manual + exclusive (synthetic FULL body):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": {\n    \"number\": \"{{purchaseReference}}\",\n    \"date\": \"2026-10-15\"\n  },\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic GST 5% Item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0,\n        \"amount\": 13.26\n      }\n    }\n  ],\n  \"narration\": \"Postman test purchase\",\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0,\n    \"amount\": 13.26\n  }\n}\n</code></pre>\n<p><strong>Manual + inclusive (synthetic FULL body):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstInclusive\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": {\n    \"number\": \"{{purchaseReference}}\",\n    \"date\": \"2026-10-15\"\n  },\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-TaxIncl.\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic GST 18% Item\"\n      },\n      \"quantity\": 0.5,\n      \"rate\": 25,\n      \"amounts\": {\n        \"taxableAmount\": 10.59,\n        \"cgst\": 0.96,\n        \"sgst\": 0.95,\n        \"igst\": 0,\n        \"amount\": 12.5\n      }\n    }\n  ],\n  \"narration\": \"Postman test purchase\",\n  \"totals\": {\n    \"taxableAmount\": 10.59,\n    \"cgst\": 0.96,\n    \"sgst\": 0.95,\n    \"igst\": 0,\n    \"amount\": 12.5\n  }\n}\n</code></pre>\n<p>The normal request's test requires 200 for a synchronous success; saved 400/409/422/502/504 examples are separate expected-refusal illustrations and do not constitute a successful create assertion. An explicit queue:true request requires 202 and must be polled for its final result.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Installed public v0.0.30 predates this merged source; these are documentation examples only. Do not Send until a newer candidate with this source is installed and the target BUSY series is verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": {\n    \"number\": \"{{purchaseReference}}\",\n    \"date\": \"2026-10-15\"\n  },\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100,\n      \"description\": [\n        \"Postman test purchase\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test purchase\",\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": {\n    \"number\": \"{{purchaseReference}}\",\n    \"date\": \"2026-10-15\"\n  },\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100,\n      \"description\": [\n        \"Postman test purchase\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test purchase\",\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","purchase-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"6226ec00-b61a-933f-a460-8e2bd20dbdfb","name":"200 – purchase with discount, freight, round-off and parameter rows (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": { \"number\": \"{{purchaseReference}}\", \"date\": \"2026-10-15\" },\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PUR SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100, \"description\": [\"Postman test purchase\"] }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-create","description":"**Local** · `POST {{baseUrl}}/api/v1/purchase-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `purchaseReference`, `date`, `supplierInvoice` (`number`, `date`), `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherNumber`, `voucherSeries`, `billSundries`, `dueDate`, `narration` · operation `busy.purchases.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.purchases.create` (`POST /api/v1/purchase-create`) creates one BUSY **purchase** through BUSY's own COM component on this PC: the supplier is credited with the total, the purchase and GST input accounts debited, the goods come into `materialCenter` at their cost. **Create only**: it never changes, cancels or deletes a purchase. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15; **installed service-account acceptance passed 2026-10-15** (COMP0002 / 2026: five purchases saved and verified, ten refusals wrote nothing); owner acceptance for customers is separate. **Through the cloud: not available** — the PC is relay-ready (same organization token, write rules), but the AI Zeny cloud has no purchase route and none is part of this work.\n\n**How it works.**\n- **Three numbers, kept apart:** your `purchaseReference` (1-60, first narration, unique among the company's purchases of the year — the retry key); the supplier's own invoice `supplierInvoice.number` (1-25, unique among that supplier's non-cancelled purchases of the year) and `date`; BUSY's `voucherNumber` (1-25, default the supplier invoice number, never empty), which must be new in the series. Only a purchase series with **manual** numbering is accepted.\n- `lines` (1-100): `item`, `quantity` (main unit, **at most 2 decimals**), `rate`, optional `discountPercent` (the rate after discount must have at most 2 decimals — never rounded for you), `mrp`, `description`, and `parameters` (required for a parameter-wise item, adding up exactly to the line; refused for any other item). GST is calculated as for a sales invoice (tax-exclusive item-wise purchase types only).\n- **Parameter-wise items** are offered only when the company's parameter setup in BUSY is one parameter (free text or a list of values): each value must fit the parameter's width and, for a list, be one of its values exactly as BUSY shows them (on COMP0002: `Size`, `Color`). Any other setup, or none, is `422 PURCHASE_ITEM_UNSUPPORTED` — an item without parameter history is never assumed to have one field.\n- `billSundries` (optional, at most 10): one percentage discount (on the lines' amounts with GST; amount half away from zero; spread over the line costs half to even, the first line taking the remainder, as BUSY's window does), fixed charges, one round-off ≤ 0.99 — only bill sundries set up like BUSY's own Discount, Freight & Forwarding Charges and Rounded Off (+)/(-).\n- For a supplier BUSY keeps bill by bill, one payable named by the supplier invoice number (optional `dueDate`; default the supplier's purchase credit days).\n- No \"purpose of purchase\" is sent (a state-VAT field; that BUSY's own default suits every setup is not proven).\n- AI Zeny compares BUSY's read-back and the saved rows (ledger, costs, sundries, payable, parameter rows, GST summary) before answering. Purchases, receipts and sales returns share one lock on the PC.\n\n**Refused before BUSY:** an unknown master (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), a reference already held (`409 PURCHASE_REFERENCE_TAKEN`, `details.purchaseId`), the supplier's invoice already entered (`409 PURCHASE_SUPPLIER_INVOICE_TAKEN`, `details.purchaseId`), a voucher number in the series (`409 PURCHASE_NUMBER_TAKEN`), a payable name the supplier already uses (`409 PURCHASE_BILL_REFERENCE_TAKEN`), an automatic series (`422 PURCHASE_SERIES_UNSUPPORTED`), a cash/bank supplier (`422 PURCHASE_SUPPLIER_UNSUPPORTED`), other purchase types or tax categories (`422 PURCHASE_TYPE_UNSUPPORTED` / `PURCHASE_TAX_UNSUPPORTED`), serial, batch, multi-parameter, unproven-parameter-setup or non-1-conversion items (`422 PURCHASE_ITEM_UNSUPPORTED`), parameter rows wrong, too long or not in the setup's list (`422 PURCHASE_PARAMETERS_INVALID`), other bill sundries or combinations (`422 PURCHASE_BILL_SUNDRY_UNSUPPORTED`), a `dueDate` for a supplier not kept bill by bill (`422 PURCHASE_DUE_DATE_UNSUPPORTED`), 3 decimals (`400`). A purpose code, billing block, amounts or XML are never accepted (`400`).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `purchaseReference` of at most 25 characters (current value) before each send — for example `AZPM-PUR-0NN`. This request uses it as the reference, the supplier invoice number and (by default) the voucher number. The request is skipped without one. Do not reuse `AZPOC-PUR-…` or `AZSVC-PUR-…` (PoC and acceptance records, including purchases 114-150).\n- The example body is one local line for the PoC's test supplier with no bill sundries; it creates a payable (the supplier is kept bill by bill).\n- Nothing is deleted automatically: a created test purchase stays in BUSY (and moves stock in).\n- **Never retry blindly.** Sending the same `purchaseReference` again is refused (`409 PURCHASE_REFERENCE_TAKEN`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `purchaseId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or payable differ (`details.purchaseId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs and the other writes), up to 2 minutes: give the request a long timeout. Body up to 128 KiB.\n\n**Sets:** `purchaseId` on success (usable as `voucherId` with `voucherType` `purchaseInvoice` in the Voucher PDF request). Public guide: `docs/public/api/purchase-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. Public guide: `docs/public/api/line-descriptions.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"purchaseId\": 8840,\n    \"voucherNumber\": \"SUP-7781\",\n    \"purchaseReference\": \"WEB-PUR-50112\",\n    \"date\": \"2026-10-15\",\n    \"voucherSeries\": { \"code\": 251, \"name\": \"Main\" },\n    \"supplier\": { \"code\": 7101, \"name\": \"Synthetic Supplies\" },\n    \"purchaseType\": { \"code\": 9312, \"name\": \"Local-ItemWise\" },\n    \"taxation\": \"local\",\n    \"materialCenter\": { \"code\": 9501, \"name\": \"Main Store\" },\n    \"supplierInvoice\": { \"number\": \"SUP-7781\", \"date\": \"2026-10-14\" },\n    \"lines\": [\n      { \"lineNumber\": 1, \"item\": { \"code\": 9401, \"name\": \"Synthetic Item\" }, \"unit\": \"Pcs.\", \"quantity\": 10, \"rate\": 120, \"discountPercent\": 0, \"netRate\": 120, \"taxableAmount\": 1200, \"cgst\": 72, \"sgst\": 72, \"igst\": 0, \"taxAmount\": 144, \"amount\": 1344, \"discountShare\": 26.88, \"cost\": 1173.12, \"mrp\": null, \"description\": [], \"parameters\": [] },\n      { \"lineNumber\": 2, \"item\": { \"code\": 9402, \"name\": \"Synthetic Colour Item\" }, \"unit\": \"Pcs.\", \"quantity\": 5, \"rate\": 80, \"discountPercent\": 0, \"netRate\": 80, \"taxableAmount\": 400, \"cgst\": 24, \"sgst\": 24, \"igst\": 0, \"taxAmount\": 48, \"amount\": 448, \"discountShare\": 8.96, \"cost\": 391.04, \"mrp\": null, \"description\": [], \"parameters\": [ { \"value\": \"RED\", \"quantity\": 3, \"amount\": 240 }, { \"value\": \"BLUE\", \"quantity\": 2, \"amount\": 160 } ] }\n    ],\n    \"billSundries\": [\n      { \"lineNumber\": 1, \"billSundry\": { \"code\": 9601, \"name\": \"Discount\" }, \"kind\": \"discount\", \"percent\": 2, \"baseAmount\": 1792, \"amount\": 35.84, \"effect\": \"subtract\" },\n      { \"lineNumber\": 2, \"billSundry\": { \"code\": 9602, \"name\": \"Freight & Forwarding Charges\" }, \"kind\": \"charge\", \"percent\": null, \"baseAmount\": null, \"amount\": 50, \"effect\": \"add\" },\n      { \"lineNumber\": 3, \"billSundry\": { \"code\": 9604, \"name\": \"Rounded Off (-)\" }, \"kind\": \"roundOff\", \"percent\": null, \"baseAmount\": null, \"amount\": 0.16, \"effect\": \"subtract\" }\n    ],\n    \"totals\": { \"quantity\": 15, \"taxableAmount\": 1600, \"cgst\": 96, \"sgst\": 96, \"igst\": 0, \"taxAmount\": 192, \"discount\": 35.84, \"charges\": 50, \"roundOff\": -0.16, \"purchaseValue\": 1564.16, \"amount\": 1806 },\n    \"billReference\": { \"number\": \"SUP-7781\", \"amount\": 1806, \"dueDate\": \"2026-11-14\" },\n    \"narration\": \"Synthetic purchase from the supplier portal\",\n    \"ledger\": [\n      { \"account\": { \"code\": 7101, \"name\": \"Synthetic Supplies\" }, \"debit\": 0, \"credit\": 1806 },\n      { \"account\": { \"code\": 9201, \"name\": \"Synthetic Purchase\" }, \"debit\": 1564.16, \"credit\": 0 },\n      { \"account\": { \"code\": 9221, \"name\": \"Synthetic Freight\" }, \"debit\": 50, \"credit\": 0 },\n      { \"account\": { \"code\": 9231, \"name\": \"Synthetic Round Off\" }, \"debit\": 0, \"credit\": 0.16 },\n      { \"account\": { \"code\": 9213, \"name\": \"Synthetic CGST Input\" }, \"debit\": 96, \"credit\": 0 },\n      { \"account\": { \"code\": 9214, \"name\": \"Synthetic SGST Input\" }, \"debit\": 96, \"credit\": 0 }\n    ]\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.purchases.create\",\n    \"requestId\": \"7d1e3a5c9b0f42e6a8c4e2b6d0f8a1c3\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 2,\n    \"verification\": [\"busyReadBack\", \"savedRows\"],\n    \"elapsedMs\": 2930,\n    \"executedAt\": \"2026-10-15T10:00:00+00:00\"\n  }\n}"},{"id":"7fa1b1d4-64bc-52f8-3105-f17c9bb0f480","name":"409 – PURCHASE_REFERENCE_TAKEN (retry after a saved purchase, synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": { \"number\": \"{{purchaseReference}}\", \"date\": \"2026-10-15\" },\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PUR SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100, \"description\": [\"Postman test purchase\"] }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-create","description":"**Local** · `POST {{baseUrl}}/api/v1/purchase-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `purchaseReference`, `date`, `supplierInvoice` (`number`, `date`), `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherNumber`, `voucherSeries`, `billSundries`, `dueDate`, `narration` · operation `busy.purchases.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.purchases.create` (`POST /api/v1/purchase-create`) creates one BUSY **purchase** through BUSY's own COM component on this PC: the supplier is credited with the total, the purchase and GST input accounts debited, the goods come into `materialCenter` at their cost. **Create only**: it never changes, cancels or deletes a purchase. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15; **installed service-account acceptance passed 2026-10-15** (COMP0002 / 2026: five purchases saved and verified, ten refusals wrote nothing); owner acceptance for customers is separate. **Through the cloud: not available** — the PC is relay-ready (same organization token, write rules), but the AI Zeny cloud has no purchase route and none is part of this work.\n\n**How it works.**\n- **Three numbers, kept apart:** your `purchaseReference` (1-60, first narration, unique among the company's purchases of the year — the retry key); the supplier's own invoice `supplierInvoice.number` (1-25, unique among that supplier's non-cancelled purchases of the year) and `date`; BUSY's `voucherNumber` (1-25, default the supplier invoice number, never empty), which must be new in the series. Only a purchase series with **manual** numbering is accepted.\n- `lines` (1-100): `item`, `quantity` (main unit, **at most 2 decimals**), `rate`, optional `discountPercent` (the rate after discount must have at most 2 decimals — never rounded for you), `mrp`, `description`, and `parameters` (required for a parameter-wise item, adding up exactly to the line; refused for any other item). GST is calculated as for a sales invoice (tax-exclusive item-wise purchase types only).\n- **Parameter-wise items** are offered only when the company's parameter setup in BUSY is one parameter (free text or a list of values): each value must fit the parameter's width and, for a list, be one of its values exactly as BUSY shows them (on COMP0002: `Size`, `Color`). Any other setup, or none, is `422 PURCHASE_ITEM_UNSUPPORTED` — an item without parameter history is never assumed to have one field.\n- `billSundries` (optional, at most 10): one percentage discount (on the lines' amounts with GST; amount half away from zero; spread over the line costs half to even, the first line taking the remainder, as BUSY's window does), fixed charges, one round-off ≤ 0.99 — only bill sundries set up like BUSY's own Discount, Freight & Forwarding Charges and Rounded Off (+)/(-).\n- For a supplier BUSY keeps bill by bill, one payable named by the supplier invoice number (optional `dueDate`; default the supplier's purchase credit days).\n- No \"purpose of purchase\" is sent (a state-VAT field; that BUSY's own default suits every setup is not proven).\n- AI Zeny compares BUSY's read-back and the saved rows (ledger, costs, sundries, payable, parameter rows, GST summary) before answering. Purchases, receipts and sales returns share one lock on the PC.\n\n**Refused before BUSY:** an unknown master (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), a reference already held (`409 PURCHASE_REFERENCE_TAKEN`, `details.purchaseId`), the supplier's invoice already entered (`409 PURCHASE_SUPPLIER_INVOICE_TAKEN`, `details.purchaseId`), a voucher number in the series (`409 PURCHASE_NUMBER_TAKEN`), a payable name the supplier already uses (`409 PURCHASE_BILL_REFERENCE_TAKEN`), an automatic series (`422 PURCHASE_SERIES_UNSUPPORTED`), a cash/bank supplier (`422 PURCHASE_SUPPLIER_UNSUPPORTED`), other purchase types or tax categories (`422 PURCHASE_TYPE_UNSUPPORTED` / `PURCHASE_TAX_UNSUPPORTED`), serial, batch, multi-parameter, unproven-parameter-setup or non-1-conversion items (`422 PURCHASE_ITEM_UNSUPPORTED`), parameter rows wrong, too long or not in the setup's list (`422 PURCHASE_PARAMETERS_INVALID`), other bill sundries or combinations (`422 PURCHASE_BILL_SUNDRY_UNSUPPORTED`), a `dueDate` for a supplier not kept bill by bill (`422 PURCHASE_DUE_DATE_UNSUPPORTED`), 3 decimals (`400`). A purpose code, billing block, amounts or XML are never accepted (`400`).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `purchaseReference` of at most 25 characters (current value) before each send — for example `AZPM-PUR-0NN`. This request uses it as the reference, the supplier invoice number and (by default) the voucher number. The request is skipped without one. Do not reuse `AZPOC-PUR-…` or `AZSVC-PUR-…` (PoC and acceptance records, including purchases 114-150).\n- The example body is one local line for the PoC's test supplier with no bill sundries; it creates a payable (the supplier is kept bill by bill).\n- Nothing is deleted automatically: a created test purchase stays in BUSY (and moves stock in).\n- **Never retry blindly.** Sending the same `purchaseReference` again is refused (`409 PURCHASE_REFERENCE_TAKEN`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `purchaseId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or payable differ (`details.purchaseId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs and the other writes), up to 2 minutes: give the request a long timeout. Body up to 128 KiB.\n\n**Sets:** `purchaseId` on success (usable as `voucherId` with `voucherType` `purchaseInvoice` in the Voucher PDF request). Public guide: `docs/public/api/purchase-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. Public guide: `docs/public/api/line-descriptions.md`."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PURCHASE_REFERENCE_TAKEN\",\n      \"message\": \"A purchase of this company and financial year already holds this purchaseReference. A create never changes an existing purchase; if your earlier call saved it, metadata.error.details.purchaseId names it.\",\n      \"field\": \"purchaseReference\",\n      \"details\": { \"purchaseId\": 8840 }\n    },\n    \"requestId\": \"3c5e7a9b1d2f44a6b8c0e2a4c6e8f0a2\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"39110ac5-fe2e-98a2-53fe-6752cb5102df","name":"409 – PURCHASE_SUPPLIER_INVOICE_TAKEN (the supplier's bill is already entered, synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": { \"number\": \"{{purchaseReference}}\", \"date\": \"2026-10-15\" },\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PUR SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100, \"description\": [\"Postman test purchase\"] }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-create","description":"**Local** · `POST {{baseUrl}}/api/v1/purchase-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `purchaseReference`, `date`, `supplierInvoice` (`number`, `date`), `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherNumber`, `voucherSeries`, `billSundries`, `dueDate`, `narration` · operation `busy.purchases.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.purchases.create` (`POST /api/v1/purchase-create`) creates one BUSY **purchase** through BUSY's own COM component on this PC: the supplier is credited with the total, the purchase and GST input accounts debited, the goods come into `materialCenter` at their cost. **Create only**: it never changes, cancels or deletes a purchase. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15; **installed service-account acceptance passed 2026-10-15** (COMP0002 / 2026: five purchases saved and verified, ten refusals wrote nothing); owner acceptance for customers is separate. **Through the cloud: not available** — the PC is relay-ready (same organization token, write rules), but the AI Zeny cloud has no purchase route and none is part of this work.\n\n**How it works.**\n- **Three numbers, kept apart:** your `purchaseReference` (1-60, first narration, unique among the company's purchases of the year — the retry key); the supplier's own invoice `supplierInvoice.number` (1-25, unique among that supplier's non-cancelled purchases of the year) and `date`; BUSY's `voucherNumber` (1-25, default the supplier invoice number, never empty), which must be new in the series. Only a purchase series with **manual** numbering is accepted.\n- `lines` (1-100): `item`, `quantity` (main unit, **at most 2 decimals**), `rate`, optional `discountPercent` (the rate after discount must have at most 2 decimals — never rounded for you), `mrp`, `description`, and `parameters` (required for a parameter-wise item, adding up exactly to the line; refused for any other item). GST is calculated as for a sales invoice (tax-exclusive item-wise purchase types only).\n- **Parameter-wise items** are offered only when the company's parameter setup in BUSY is one parameter (free text or a list of values): each value must fit the parameter's width and, for a list, be one of its values exactly as BUSY shows them (on COMP0002: `Size`, `Color`). Any other setup, or none, is `422 PURCHASE_ITEM_UNSUPPORTED` — an item without parameter history is never assumed to have one field.\n- `billSundries` (optional, at most 10): one percentage discount (on the lines' amounts with GST; amount half away from zero; spread over the line costs half to even, the first line taking the remainder, as BUSY's window does), fixed charges, one round-off ≤ 0.99 — only bill sundries set up like BUSY's own Discount, Freight & Forwarding Charges and Rounded Off (+)/(-).\n- For a supplier BUSY keeps bill by bill, one payable named by the supplier invoice number (optional `dueDate`; default the supplier's purchase credit days).\n- No \"purpose of purchase\" is sent (a state-VAT field; that BUSY's own default suits every setup is not proven).\n- AI Zeny compares BUSY's read-back and the saved rows (ledger, costs, sundries, payable, parameter rows, GST summary) before answering. Purchases, receipts and sales returns share one lock on the PC.\n\n**Refused before BUSY:** an unknown master (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), a reference already held (`409 PURCHASE_REFERENCE_TAKEN`, `details.purchaseId`), the supplier's invoice already entered (`409 PURCHASE_SUPPLIER_INVOICE_TAKEN`, `details.purchaseId`), a voucher number in the series (`409 PURCHASE_NUMBER_TAKEN`), a payable name the supplier already uses (`409 PURCHASE_BILL_REFERENCE_TAKEN`), an automatic series (`422 PURCHASE_SERIES_UNSUPPORTED`), a cash/bank supplier (`422 PURCHASE_SUPPLIER_UNSUPPORTED`), other purchase types or tax categories (`422 PURCHASE_TYPE_UNSUPPORTED` / `PURCHASE_TAX_UNSUPPORTED`), serial, batch, multi-parameter, unproven-parameter-setup or non-1-conversion items (`422 PURCHASE_ITEM_UNSUPPORTED`), parameter rows wrong, too long or not in the setup's list (`422 PURCHASE_PARAMETERS_INVALID`), other bill sundries or combinations (`422 PURCHASE_BILL_SUNDRY_UNSUPPORTED`), a `dueDate` for a supplier not kept bill by bill (`422 PURCHASE_DUE_DATE_UNSUPPORTED`), 3 decimals (`400`). A purpose code, billing block, amounts or XML are never accepted (`400`).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `purchaseReference` of at most 25 characters (current value) before each send — for example `AZPM-PUR-0NN`. This request uses it as the reference, the supplier invoice number and (by default) the voucher number. The request is skipped without one. Do not reuse `AZPOC-PUR-…` or `AZSVC-PUR-…` (PoC and acceptance records, including purchases 114-150).\n- The example body is one local line for the PoC's test supplier with no bill sundries; it creates a payable (the supplier is kept bill by bill).\n- Nothing is deleted automatically: a created test purchase stays in BUSY (and moves stock in).\n- **Never retry blindly.** Sending the same `purchaseReference` again is refused (`409 PURCHASE_REFERENCE_TAKEN`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `purchaseId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or payable differ (`details.purchaseId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs and the other writes), up to 2 minutes: give the request a long timeout. Body up to 128 KiB.\n\n**Sets:** `purchaseId` on success (usable as `voucherId` with `voucherType` `purchaseInvoice` in the Voucher PDF request). Public guide: `docs/public/api/purchase-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. Public guide: `docs/public/api/line-descriptions.md`."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PURCHASE_SUPPLIER_INVOICE_TAKEN\",\n      \"message\": \"A purchase from this supplier in this financial year already records this supplier invoice number (metadata.error.details.purchaseId). The same bill is not entered twice; check it in BUSY.\",\n      \"field\": \"supplierInvoice.number\",\n      \"details\": { \"purchaseId\": 8840 }\n    },\n    \"requestId\": \"9a1c3e5f7b2d46a8c0e2b4d6f8a0c2e4\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"a227e295-35dd-2abe-37fe-086e7e81e8e7","name":"422 – PURCHASE_BILL_SUNDRY_UNSUPPORTED (a bill sundry set up otherwise, synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": { \"number\": \"{{purchaseReference}}\", \"date\": \"2026-10-15\" },\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PUR SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100, \"description\": [\"Postman test purchase\"] }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-create","description":"**Local** · `POST {{baseUrl}}/api/v1/purchase-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `purchaseReference`, `date`, `supplierInvoice` (`number`, `date`), `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherNumber`, `voucherSeries`, `billSundries`, `dueDate`, `narration` · operation `busy.purchases.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.purchases.create` (`POST /api/v1/purchase-create`) creates one BUSY **purchase** through BUSY's own COM component on this PC: the supplier is credited with the total, the purchase and GST input accounts debited, the goods come into `materialCenter` at their cost. **Create only**: it never changes, cancels or deletes a purchase. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15; **installed service-account acceptance passed 2026-10-15** (COMP0002 / 2026: five purchases saved and verified, ten refusals wrote nothing); owner acceptance for customers is separate. **Through the cloud: not available** — the PC is relay-ready (same organization token, write rules), but the AI Zeny cloud has no purchase route and none is part of this work.\n\n**How it works.**\n- **Three numbers, kept apart:** your `purchaseReference` (1-60, first narration, unique among the company's purchases of the year — the retry key); the supplier's own invoice `supplierInvoice.number` (1-25, unique among that supplier's non-cancelled purchases of the year) and `date`; BUSY's `voucherNumber` (1-25, default the supplier invoice number, never empty), which must be new in the series. Only a purchase series with **manual** numbering is accepted.\n- `lines` (1-100): `item`, `quantity` (main unit, **at most 2 decimals**), `rate`, optional `discountPercent` (the rate after discount must have at most 2 decimals — never rounded for you), `mrp`, `description`, and `parameters` (required for a parameter-wise item, adding up exactly to the line; refused for any other item). GST is calculated as for a sales invoice (tax-exclusive item-wise purchase types only).\n- **Parameter-wise items** are offered only when the company's parameter setup in BUSY is one parameter (free text or a list of values): each value must fit the parameter's width and, for a list, be one of its values exactly as BUSY shows them (on COMP0002: `Size`, `Color`). Any other setup, or none, is `422 PURCHASE_ITEM_UNSUPPORTED` — an item without parameter history is never assumed to have one field.\n- `billSundries` (optional, at most 10): one percentage discount (on the lines' amounts with GST; amount half away from zero; spread over the line costs half to even, the first line taking the remainder, as BUSY's window does), fixed charges, one round-off ≤ 0.99 — only bill sundries set up like BUSY's own Discount, Freight & Forwarding Charges and Rounded Off (+)/(-).\n- For a supplier BUSY keeps bill by bill, one payable named by the supplier invoice number (optional `dueDate`; default the supplier's purchase credit days).\n- No \"purpose of purchase\" is sent (a state-VAT field; that BUSY's own default suits every setup is not proven).\n- AI Zeny compares BUSY's read-back and the saved rows (ledger, costs, sundries, payable, parameter rows, GST summary) before answering. Purchases, receipts and sales returns share one lock on the PC.\n\n**Refused before BUSY:** an unknown master (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), a reference already held (`409 PURCHASE_REFERENCE_TAKEN`, `details.purchaseId`), the supplier's invoice already entered (`409 PURCHASE_SUPPLIER_INVOICE_TAKEN`, `details.purchaseId`), a voucher number in the series (`409 PURCHASE_NUMBER_TAKEN`), a payable name the supplier already uses (`409 PURCHASE_BILL_REFERENCE_TAKEN`), an automatic series (`422 PURCHASE_SERIES_UNSUPPORTED`), a cash/bank supplier (`422 PURCHASE_SUPPLIER_UNSUPPORTED`), other purchase types or tax categories (`422 PURCHASE_TYPE_UNSUPPORTED` / `PURCHASE_TAX_UNSUPPORTED`), serial, batch, multi-parameter, unproven-parameter-setup or non-1-conversion items (`422 PURCHASE_ITEM_UNSUPPORTED`), parameter rows wrong, too long or not in the setup's list (`422 PURCHASE_PARAMETERS_INVALID`), other bill sundries or combinations (`422 PURCHASE_BILL_SUNDRY_UNSUPPORTED`), a `dueDate` for a supplier not kept bill by bill (`422 PURCHASE_DUE_DATE_UNSUPPORTED`), 3 decimals (`400`). A purpose code, billing block, amounts or XML are never accepted (`400`).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `purchaseReference` of at most 25 characters (current value) before each send — for example `AZPM-PUR-0NN`. This request uses it as the reference, the supplier invoice number and (by default) the voucher number. The request is skipped without one. Do not reuse `AZPOC-PUR-…` or `AZSVC-PUR-…` (PoC and acceptance records, including purchases 114-150).\n- The example body is one local line for the PoC's test supplier with no bill sundries; it creates a payable (the supplier is kept bill by bill).\n- Nothing is deleted automatically: a created test purchase stays in BUSY (and moves stock in).\n- **Never retry blindly.** Sending the same `purchaseReference` again is refused (`409 PURCHASE_REFERENCE_TAKEN`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `purchaseId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or payable differ (`details.purchaseId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs and the other writes), up to 2 minutes: give the request a long timeout. Body up to 128 KiB.\n\n**Sets:** `purchaseId` on success (usable as `voucherId` with `voucherType` `purchaseInvoice` in the Voucher PDF request). Public guide: `docs/public/api/purchase-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. Public guide: `docs/public/api/line-descriptions.md`."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PURCHASE_BILL_SUNDRY_UNSUPPORTED\",\n      \"message\": \"AI Zeny creates purchases only with a percentage discount on the purchase value (with GST included), fixed additive charges posting to their own account, and a round-off, each set up as BUSY's own Discount, Freight & Forwarding Charges and Rounded Off (+) / (-) are. This bill sundry is set up otherwise. Enter this purchase in BUSY.\",\n      \"field\": \"billSundries[0].billSundry\"\n    },\n    \"requestId\": \"b2d4f6a8c0e246b8d0f2a4c6e8b0d2f4\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"47d50b1e-f069-25c8-38b4-9f5bfeb7902d","name":"504 – BUSY_WRITE_UNCERTAIN (reconciled: found, synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": { \"number\": \"{{purchaseReference}}\", \"date\": \"2026-10-15\" },\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PUR SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100, \"description\": [\"Postman test purchase\"] }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-create","description":"**Local** · `POST {{baseUrl}}/api/v1/purchase-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `purchaseReference`, `date`, `supplierInvoice` (`number`, `date`), `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherNumber`, `voucherSeries`, `billSundries`, `dueDate`, `narration` · operation `busy.purchases.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.purchases.create` (`POST /api/v1/purchase-create`) creates one BUSY **purchase** through BUSY's own COM component on this PC: the supplier is credited with the total, the purchase and GST input accounts debited, the goods come into `materialCenter` at their cost. **Create only**: it never changes, cancels or deletes a purchase. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15; **installed service-account acceptance passed 2026-10-15** (COMP0002 / 2026: five purchases saved and verified, ten refusals wrote nothing); owner acceptance for customers is separate. **Through the cloud: not available** — the PC is relay-ready (same organization token, write rules), but the AI Zeny cloud has no purchase route and none is part of this work.\n\n**How it works.**\n- **Three numbers, kept apart:** your `purchaseReference` (1-60, first narration, unique among the company's purchases of the year — the retry key); the supplier's own invoice `supplierInvoice.number` (1-25, unique among that supplier's non-cancelled purchases of the year) and `date`; BUSY's `voucherNumber` (1-25, default the supplier invoice number, never empty), which must be new in the series. Only a purchase series with **manual** numbering is accepted.\n- `lines` (1-100): `item`, `quantity` (main unit, **at most 2 decimals**), `rate`, optional `discountPercent` (the rate after discount must have at most 2 decimals — never rounded for you), `mrp`, `description`, and `parameters` (required for a parameter-wise item, adding up exactly to the line; refused for any other item). GST is calculated as for a sales invoice (tax-exclusive item-wise purchase types only).\n- **Parameter-wise items** are offered only when the company's parameter setup in BUSY is one parameter (free text or a list of values): each value must fit the parameter's width and, for a list, be one of its values exactly as BUSY shows them (on COMP0002: `Size`, `Color`). Any other setup, or none, is `422 PURCHASE_ITEM_UNSUPPORTED` — an item without parameter history is never assumed to have one field.\n- `billSundries` (optional, at most 10): one percentage discount (on the lines' amounts with GST; amount half away from zero; spread over the line costs half to even, the first line taking the remainder, as BUSY's window does), fixed charges, one round-off ≤ 0.99 — only bill sundries set up like BUSY's own Discount, Freight & Forwarding Charges and Rounded Off (+)/(-).\n- For a supplier BUSY keeps bill by bill, one payable named by the supplier invoice number (optional `dueDate`; default the supplier's purchase credit days).\n- No \"purpose of purchase\" is sent (a state-VAT field; that BUSY's own default suits every setup is not proven).\n- AI Zeny compares BUSY's read-back and the saved rows (ledger, costs, sundries, payable, parameter rows, GST summary) before answering. Purchases, receipts and sales returns share one lock on the PC.\n\n**Refused before BUSY:** an unknown master (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), a reference already held (`409 PURCHASE_REFERENCE_TAKEN`, `details.purchaseId`), the supplier's invoice already entered (`409 PURCHASE_SUPPLIER_INVOICE_TAKEN`, `details.purchaseId`), a voucher number in the series (`409 PURCHASE_NUMBER_TAKEN`), a payable name the supplier already uses (`409 PURCHASE_BILL_REFERENCE_TAKEN`), an automatic series (`422 PURCHASE_SERIES_UNSUPPORTED`), a cash/bank supplier (`422 PURCHASE_SUPPLIER_UNSUPPORTED`), other purchase types or tax categories (`422 PURCHASE_TYPE_UNSUPPORTED` / `PURCHASE_TAX_UNSUPPORTED`), serial, batch, multi-parameter, unproven-parameter-setup or non-1-conversion items (`422 PURCHASE_ITEM_UNSUPPORTED`), parameter rows wrong, too long or not in the setup's list (`422 PURCHASE_PARAMETERS_INVALID`), other bill sundries or combinations (`422 PURCHASE_BILL_SUNDRY_UNSUPPORTED`), a `dueDate` for a supplier not kept bill by bill (`422 PURCHASE_DUE_DATE_UNSUPPORTED`), 3 decimals (`400`). A purpose code, billing block, amounts or XML are never accepted (`400`).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `purchaseReference` of at most 25 characters (current value) before each send — for example `AZPM-PUR-0NN`. This request uses it as the reference, the supplier invoice number and (by default) the voucher number. The request is skipped without one. Do not reuse `AZPOC-PUR-…` or `AZSVC-PUR-…` (PoC and acceptance records, including purchases 114-150).\n- The example body is one local line for the PoC's test supplier with no bill sundries; it creates a payable (the supplier is kept bill by bill).\n- Nothing is deleted automatically: a created test purchase stays in BUSY (and moves stock in).\n- **Never retry blindly.** Sending the same `purchaseReference` again is refused (`409 PURCHASE_REFERENCE_TAKEN`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `purchaseId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or payable differ (`details.purchaseId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC (shared with voucher PDFs and the other writes), up to 2 minutes: give the request a long timeout. Body up to 128 KiB.\n\n**Sets:** `purchaseId` on success (usable as `voucherId` with `voucherType` `purchaseInvoice` in the Voucher PDF request). Public guide: `docs/public/api/purchase-create.md`.\n\n**Line descriptions (owner acceptance 2026-10-19; `docs/features/BUSY-Voucher-Line-Descriptions.md`):** `lines[].description` is the voucher line's own text (not the item's): 1-10 positions of up to 40 characters, trimmed; `\"\"` or `null` keeps a position empty; trailing empty positions dropped; at least one text. The voucher series must have item-wise descriptions on in BUSY with at least as many lines — otherwise `422 BUSY_SETTING_REQUIRED` (`lines[i].description`) or `422 DESCRIPTION_LINE_NOT_ALLOWED` (`lines[i].description[n]`), nothing saved. SQL Server companies take Latin-1 characters only (`400`, before BUSY); Access companies any text. The answer's lines carry `description` as saved. Public guide: `docs/public/api/line-descriptions.md`."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"BUSY stopped while saving the purchase; a purchase with this purchaseReference exists now (metadata.error.details.purchaseId). Check it in BUSY; do not send it again.\",\n      \"details\": { \"purchaseId\": 8841, \"reconciliation\": \"found\" }\n    },\n    \"requestId\": \"d4f6a8c0e2b448d0f2a4c6e8a0c2e4f6\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"73cfbefb-57b0-033b-4bd8-f1d72bf432fa","name":"409 – GST_CONFIGURATION_CHANGED (before save)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": {\n    \"number\": \"{{purchaseReference}}\",\n    \"date\": \"2026-10-15\"\n  },\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic 5% item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0,\n        \"amount\": 13.26\n      }\n    }\n  ],\n  \"narration\": \"Postman test purchase\",\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0,\n    \"amount\": 13.26\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"GST_CONFIGURATION_CHANGED\",\n      \"message\": \"BUSY's selected GST or voucher-series configuration changed while this request was being prepared. Read it again and submit a new request.\"\n    }\n  }\n}"},{"id":"f5159ed6-c05f-9e85-e2ff-c1530a348506","name":"422 – GST_AMOUNTS_INVALID (manual treatment)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": {\n    \"number\": \"{{purchaseReference}}\",\n    \"date\": \"2026-10-15\"\n  },\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic 5% item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0.05,\n        \"amount\": 13.31\n      }\n    }\n  ],\n  \"narration\": \"Postman test purchase\",\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0.05,\n    \"amount\": 13.31\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-create"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"GST_AMOUNTS_INVALID\",\n      \"message\": \"Manual GST amounts conflict with the selected tax rate or local/central treatment.\"\n    }\n  }\n}"},{"id":"4ef7b53c-303b-f40b-cb66-afc4e8ce0e57","name":"502 – BUSY_WRITE_UNVERIFIED (saved; reconcile)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": {\n    \"number\": \"{{purchaseReference}}\",\n    \"date\": \"2026-10-15\"\n  },\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic 5% item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0,\n        \"amount\": 13.26\n      }\n    }\n  ],\n  \"narration\": \"Postman test purchase\",\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0,\n    \"amount\": 13.26\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-create"},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNVERIFIED\",\n      \"message\": \"BUSY saved the voucher but read-back differs; inspect the saved reference and do not resend.\"\n    }\n  }\n}"},{"id":"b9628805-1d2f-e747-57ca-0b2bc925e6b6","name":"400 – INVALID_PARAMETER (Manual breakdown missing)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": {\n    \"number\": \"{{purchaseReference}}\",\n    \"date\": \"2026-10-15\"\n  },\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100,\n      \"description\": [\n        \"Postman test purchase\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-create"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"Manual GST breakdown is required for every line and document totals.\"\n    }\n  }\n}"},{"id":"bba6d7e8-813d-0dc8-8222-7725bf76e743","name":"422 – GST_MODE_UNSUPPORTED (Purchase bill sundry)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstInclusive\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": {\n    \"number\": \"{{purchaseReference}}\",\n    \"date\": \"2026-10-15\"\n  },\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100,\n      \"description\": [\n        \"Postman test purchase\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test purchase\",\n  \"billSundries\": [\n    {\n      \"billSundry\": {\n        \"name\": \"Freight & Forwarding Charges\"\n      },\n      \"amount\": 1\n    }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-create"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"GST_MODE_UNSUPPORTED\",\n      \"message\": \"This new GST mode and linked/allocated/sundry combination requires separate native proof.\",\n      \"field\": \"billSundries\"\n    }\n  }\n}"},{"id":"940928f5-6a31-8e89-c852-ebc82daa935e","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": {\n    \"number\": \"{{purchaseReference}}\",\n    \"date\": \"2026-10-15\"\n  },\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100,\n      \"description\": [\n        \"Postman test purchase\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test purchase\",\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-create"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"synthetic-queue-001"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.purchases.create\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"}],"_postman_id":"b155cae7-f27b-aa61-d1f3-a71bb54bc1e3"},{"name":"⚠ BUSY purchase return – create (writes to BUSY)","id":"09a72907-d91c-8710-d15d-83c0288e9fe9","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PRT SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100 }\n  ],\n  \"adjustment\": { \"newReference\": { \"number\": \"{{purchaseReturnReference}}\" } },\n  \"narration\": \"Postman test purchase return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-return-create","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/purchase-return-create</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>⚠ Writes to BUSY</strong> (Development Local Send requires no separate confirmation)\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>returnReference</code>, <code>date</code>, <code>voucherNumber</code>, <code>supplier</code>, <code>purchaseType</code>, <code>materialCenter</code>, <code>lines</code>; <code>adjustment</code> for a supplier kept bill by bill · <strong>Optional:</strong> <code>voucherSeries</code>, <code>originalPurchase</code>, <code>billSundries</code>, <code>narration</code> · operation <code>busy.purchase-returns.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books. Run manually, one at a time.</strong> <code>busy.purchase-returns.create</code> (<code>POST /api/v1/purchase-return-create</code>) creates one BUSY <strong>purchase return / debit note</strong> through BUSY's own COM component on this PC: the supplier is debited with the total, the purchase and GST input accounts credited, the goods leave <code>materialCenter</code> at their cost. <strong>Create only</strong>: it never changes, cancels or deletes a return. <strong>SQL Server companies with a SQL login, or Access companies</strong>. Never run from scripts. <strong>Status:</strong> implemented 2026-10-15 (<code>3ee32d4</code>); <strong>installed service-account acceptance passed 2026-10-15</strong> (COMP0002 / 2026: six returns against fresh originals saved and verified by SQL and BUSY's own XML, eleven refusals wrote nothing); owner acceptance for customers is separate. <strong>Through the cloud: not available</strong> — the PC is relay-ready (same organization token, write rules), but the AI Zeny cloud has no purchase-return route.</p>\n<p><strong>How it works.</strong></p>\n<ul>\n<li><strong>Two numbers, kept apart:</strong> your <code>returnReference</code> (1-60, first narration, unique among the company's purchase returns of the year — the retry key) and your debit-note <code>voucherNumber</code> (1-25, new in the purchase-return series; also recorded as the return's own bill number and date). Only a series with <strong>manual</strong> numbering is accepted.</li>\n<li><code>lines</code> (1-100): positive values — <code>item</code>, <code>quantity</code> (main unit, <strong>at most 2 decimals</strong>), <code>rate</code>, optional <code>discountPercent</code> (the rate after discount must have at most 2 decimals — never rounded), <code>parameters</code> (required for a parameter-wise item; the purchase's parameter-setup rules). No <code>mrp</code> or <code>description</code>.</li>\n<li><code>originalPurchase</code> (optional, <code>voucherId</code> or <code>supplierInvoiceNumber</code>): the supplier's own live purchase, not later than the return, same local/central kind. Each item and parameter value is then capped at what it bought less earlier live returns naming it; an unattributable history is refused. <strong>Without it there is no quantity ceiling; returns naming no purchase never count; stock is not checked.</strong></li>\n<li>For a supplier BUSY keeps bill by bill, <code>adjustment</code> must cover the <strong>whole total</strong>: <code>againstOriginalPurchase</code> (the original's payable, never over-settled; default the smaller of the total and what it owes) and <code>newReference</code> (a new number for the rest, due on the return's date; no due date of its own). Allocations are sent negative. A supplier not kept bill by bill takes no <code>adjustment</code>.</li>\n<li><code>billSundries</code> (optional): fixed charges and one Rounded Off (-) ≤ 0.99. A discount and Rounded Off (+) are refused.</li>\n<li>No purpose code or billing is sent. AI Zeny compares BUSY's read-back, the saved rows (signs, ledger, bill rows, parameter rows, GST summary, the link) and the supplier's bills before answering. Purchase returns, purchases, receipts and sales returns share one lock on the PC.</li>\n</ul>\n<p><strong>Refused before BUSY:</strong> an unknown master (<code>422 MASTER_REFERENCE_NOT_FOUND</code>; BUSY would create it), a reference already held (<code>409 PURCHASE_RETURN_REFERENCE_TAKEN</code>, <code>details.purchaseReturnId</code>), a number in the series (<code>409 PURCHASE_RETURN_NUMBER_TAKEN</code>), a held new-reference name (<code>409 PURCHASE_RETURN_NEW_REFERENCE_TAKEN</code>), more than the original still has (<code>422 PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE</code>), an ambiguous original or history (<code>422 PURCHASE_RETURN_ORIGINAL_AMBIGUOUS</code> / <code>PURCHASE_RETURN_HISTORY_AMBIGUOUS</code>), over-settlement (<code>422 PURCHASE_RETURN_BILL_OVERSETTLED</code>), a missing or unwanted adjustment (<code>422 PURCHASE_RETURN_ADJUSTMENT_REQUIRED</code> / <code>_UNSUPPORTED</code>), an automatic series, other purchase types, tracked items, other bill sundries (<code>422</code>), 3 decimals (<code>400</code>).</p>\n<p><strong>Safe test guidance</strong></p>\n<ul>\n<li>Select a development-test <code>companyCode</code> (<code>COMP0002</code> / FY 2026 in this environment; use <code>COMP0001</code> for Access tests). With <code>autoVoucherReferences=yes</code>, each Local Send generates and stores a fresh 25-character synthetic <code>purchaseReturnReference</code>. Set that switch to <code>no</code> to supply your own unique reference. The reference is also the voucher number and new debit reference number. Do not reuse <code>AZPOC-PRT-…</code> or <code>AZSVC-PRT-…</code> (PoC and acceptance records: suppliers 1364-1367, originals 151-154 and 174-177, returns 155-173 and 178-183).</li>\n<li>The example body is one local line for the PoC's bill-by-bill test supplier, without an original purchase, its whole total as a new debit reference. To test against an original, add <code>originalPurchase</code> and <code>adjustment.againstOriginalPurchase</code> with a fresh dedicated test purchase.</li>\n<li>Nothing is deleted automatically: a created test return stays in BUSY (and moves stock out).</li>\n<li><strong>Never retry blindly.</strong> Automatic references change on each Send, so another Send can create another voucher; reconcile an uncertain result first. Sending the same <code>purchaseReturnReference</code> again is refused (<code>409 PURCHASE_RETURN_REFERENCE_TAKEN</code>) if the first send saved. After <code>504 BUSY_WRITE_UNCERTAIN</code>, read <code>metadata.error.details.reconciliation</code> (<code>found</code> + <code>purchaseReturnId</code>, <code>notFound</code>, <code>notChecked</code>) and check BUSY first.</li>\n<li><code>502 BUSY_WRITE_UNVERIFIED</code> means BUSY <strong>did</strong> save but its read-back, saved rows or the supplier's bills differ (<code>details.purchaseReturnId</code>, <code>details.mismatchedFields</code>).</li>\n<li>One BUSY job at a time on the PC, up to 2 minutes: give the request a long timeout. Body up to 128 KiB.</li>\n</ul>\n<p><strong>Sets:</strong> <code>purchaseReturnId</code> on success (usable as <code>voucherId</code> with <code>voucherType</code> <code>purchaseReturn</code> in the Voucher PDF request). Public guide: <code>docs/public/api/purchase-return-create.md</code>.</p>\n<p><strong>GST billing modes (bounded internal 0.0.15 candidate accepted 2026-10-20 on Access and SQL Server; 0.0.16 release smoke was narrower):</strong> Optional <code>taxCalculation</code> is <code>auto</code> (default) or <code>manual</code>; optional <code>pricingMode</code> is <code>gstExclusive</code> (default) or <code>gstInclusive</code>. JSON <code>null</code> selects each default. One pricing mode applies to every line. <code>rate</code> is the unit price before discount, GST included only for <code>gstInclusive</code>; choose a native item-wise sale/purchase type whose inclusive setting matches. Tax rates come from each selected item's configured category for this company/year; local uses CGST+SGST, central uses IGST. Mixed-rate lines are allowed. Auto computes money using decimal arithmetic. Manual requires every line's <code>amounts</code> and document <code>totals</code>, each with <code>taxableAmount</code>, <code>cgst</code>, <code>sgst</code>, <code>igst</code>, <code>amount</code> (JSON numbers, max two decimals). <code>amount</code> equals taxable plus components; totals equal exact line sums. Local IGST and central CGST/SGST must be zero; submitted values must satisfy the narrow configured-rate and one-paisa bounds in <code>docs/features/BUSY-GST-Billing-Modes-Create-API.md</code>. No balancing charge or silent replacement. Returns submit positive amounts; BUSY posts reversal signs. Malformed JSON or unknown fields: <code>400 BAD_REQUEST</code>; missing or inconsistent Manual amounts: <code>400 INVALID_PARAMETER</code>; invalid configured-rate/treatment: <code>422 GST_AMOUNTS_INVALID</code>; unproven new-mode combination: <code>422 GST_MODE_UNSUPPORTED</code>; changed configuration before save: <code>409 GST_CONFIGURATION_CHANGED</code>. If saved read-back mismatches: <code>502 BUSY_WRITE_UNVERIFIED</code> means saved and requires reconciliation, never automatic retry. Linked returns and bill allocations, manual Purchase sundry discounts, and zero/exempt/nil treatment are not proven for new modes; existing Auto/exclusive supported flows remain. Cloud routes are not claimed deployed.</p>\n<p><strong>Mode payload examples</strong> (fragments; retain the route's company/year/date/reference/party/series/centre fields and use a matching configured native type):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\"taxCalculation\":\"auto\",\"pricingMode\":\"gstExclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 5% item\"},\"quantity\":1.25,\"rate\":10.10}]}\n{\"taxCalculation\":\"auto\",\"pricingMode\":\"gstInclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 18% item\"},\"quantity\":0.5,\"rate\":25.00}]}\n{\"taxCalculation\":\"manual\",\"pricingMode\":\"gstExclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 5% item\"},\"quantity\":1.25,\"rate\":10.10,\"amounts\":{\"taxableAmount\":12.62,\"cgst\":0.32,\"sgst\":0.32,\"igst\":0,\"amount\":13.26}}],\"totals\":{\"taxableAmount\":12.62,\"cgst\":0.32,\"sgst\":0.32,\"igst\":0,\"amount\":13.26}}\n{\"taxCalculation\":\"manual\",\"pricingMode\":\"gstInclusive\",\"lines\":[{\"item\":{\"name\":\"Synthetic 18% item\"},\"quantity\":0.5,\"rate\":25.00,\"amounts\":{\"taxableAmount\":10.59,\"cgst\":0.96,\"sgst\":0.95,\"igst\":0,\"amount\":12.50}}],\"totals\":{\"taxableAmount\":10.59,\"cgst\":0.96,\"sgst\":0.95,\"igst\":0,\"amount\":12.50}}\n</code></pre>\n<p><strong>Mixed-rate Manual inclusive example:</strong> one 5% line may use a different configured tax category from an 18% line; sum every five amounts members exactly into totals. For central treatment replace both local components with IGST under the selected central native type. The one-paisa 18% example above shows the corrected CGST/SGST mapping. These are synthetic fragments, not live execution records.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n<h2 id=\"full-synthetic-gst-request-examples-local-only\">FULL synthetic GST request examples (Local only)</h2>\n<p>The raw Body tab above stays the minimal Auto/exclusive request. These separate complete bodies assume existing synthetic 5%/18% item tax categories, a matching item-wise native type, series, party and centre in the selected company/FY; replace fixture names and use a fresh reference before any send. <code>Local-TaxIncl.</code> must be configured with inclusive B13. Every line shares the voucher pricing mode. The amounts below are local CGST/SGST examples; for interstate treatment select the matching Central type and supply IGST instead. Return amounts remain positive in the request and BUSY reverses the postings. Do not infer Cloud Relay deployment from these Windows Local examples.</p>\n<p><strong>Auto + inclusive (synthetic FULL body):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstInclusive\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PRT SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-TaxIncl.\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic GST 18% Item\"\n      },\n      \"quantity\": 0.5,\n      \"rate\": 25\n    }\n  ],\n  \"adjustment\": {\n    \"newReference\": {\n      \"number\": \"{{purchaseReturnReference}}\"\n    }\n  },\n  \"narration\": \"Postman test purchase return\"\n}\n</code></pre>\n<p><strong>Manual + exclusive (synthetic FULL body):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PRT SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic GST 5% Item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0,\n        \"amount\": 13.26\n      }\n    }\n  ],\n  \"adjustment\": {\n    \"newReference\": {\n      \"number\": \"{{purchaseReturnReference}}\"\n    }\n  },\n  \"narration\": \"Postman test purchase return\",\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0,\n    \"amount\": 13.26\n  }\n}\n</code></pre>\n<p><strong>Manual + inclusive (synthetic FULL body):</strong></p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstInclusive\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PRT SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-TaxIncl.\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic GST 18% Item\"\n      },\n      \"quantity\": 0.5,\n      \"rate\": 25,\n      \"amounts\": {\n        \"taxableAmount\": 10.59,\n        \"cgst\": 0.96,\n        \"sgst\": 0.95,\n        \"igst\": 0,\n        \"amount\": 12.5\n      }\n    }\n  ],\n  \"adjustment\": {\n    \"newReference\": {\n      \"number\": \"{{purchaseReturnReference}}\"\n    }\n  },\n  \"narration\": \"Postman test purchase return\",\n  \"totals\": {\n    \"taxableAmount\": 10.59,\n    \"cgst\": 0.96,\n    \"sgst\": 0.95,\n    \"igst\": 0,\n    \"amount\": 12.5\n  }\n}\n</code></pre>\n<p>The normal request's test requires 200 for a synchronous success; saved 400/409/422/502/504 examples are separate expected-refusal illustrations and do not constitute a successful create assertion. An explicit queue:true request requires 202 and must be polled for its final result.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Installed public v0.0.30 predates this merged source; these are documentation examples only. Do not Send until a newer candidate with this source is installed and the target BUSY series is verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"0007-A\",\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PRT SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100\n    }\n  ],\n  \"adjustment\": {\n    \"newReference\": {\n      \"number\": \"{{purchaseReturnReference}}\"\n    }\n  },\n  \"narration\": \"Postman test purchase return\",\n  \"numberingMode\": \"manual\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PRT SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100\n    }\n  ],\n  \"adjustment\": {\n    \"newReference\": {\n      \"number\": \"{{purchaseReturnReference}}\"\n    }\n  },\n  \"narration\": \"Postman test purchase return\",\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","purchase-return-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"c4fe41e4-b243-9b02-bff0-b3e9c2cd52c3","name":"200 created – against the original + new reference (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PRT SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100 }\n  ],\n  \"adjustment\": { \"newReference\": { \"number\": \"{{purchaseReturnReference}}\" } },\n  \"narration\": \"Postman test purchase return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-return-create","description":"**Local** · `POST {{baseUrl}}/api/v1/purchase-return-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `voucherNumber`, `supplier`, `purchaseType`, `materialCenter`, `lines`; `adjustment` for a supplier kept bill by bill · **Optional:** `voucherSeries`, `originalPurchase`, `billSundries`, `narration` · operation `busy.purchase-returns.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.purchase-returns.create` (`POST /api/v1/purchase-return-create`) creates one BUSY **purchase return / debit note** through BUSY's own COM component on this PC: the supplier is debited with the total, the purchase and GST input accounts credited, the goods leave `materialCenter` at their cost. **Create only**: it never changes, cancels or deletes a return. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15 (`3ee32d4`); **installed service-account acceptance passed 2026-10-15** (COMP0002 / 2026: six returns against fresh originals saved and verified by SQL and BUSY's own XML, eleven refusals wrote nothing); owner acceptance for customers is separate. **Through the cloud: not available** — the PC is relay-ready (same organization token, write rules), but the AI Zeny cloud has no purchase-return route.\n\n**How it works.**\n- **Two numbers, kept apart:** your `returnReference` (1-60, first narration, unique among the company's purchase returns of the year — the retry key) and your debit-note `voucherNumber` (1-25, new in the purchase-return series; also recorded as the return's own bill number and date). Only a series with **manual** numbering is accepted.\n- `lines` (1-100): positive values — `item`, `quantity` (main unit, **at most 2 decimals**), `rate`, optional `discountPercent` (the rate after discount must have at most 2 decimals — never rounded), `parameters` (required for a parameter-wise item; the purchase's parameter-setup rules). No `mrp` or `description`.\n- `originalPurchase` (optional, `voucherId` or `supplierInvoiceNumber`): the supplier's own live purchase, not later than the return, same local/central kind. Each item and parameter value is then capped at what it bought less earlier live returns naming it; an unattributable history is refused. **Without it there is no quantity ceiling; returns naming no purchase never count; stock is not checked.**\n- For a supplier BUSY keeps bill by bill, `adjustment` must cover the **whole total**: `againstOriginalPurchase` (the original's payable, never over-settled; default the smaller of the total and what it owes) and `newReference` (a new number for the rest, due on the return's date; no due date of its own). Allocations are sent negative. A supplier not kept bill by bill takes no `adjustment`.\n- `billSundries` (optional): fixed charges and one Rounded Off (-) ≤ 0.99. A discount and Rounded Off (+) are refused.\n- No purpose code or billing is sent. AI Zeny compares BUSY's read-back, the saved rows (signs, ledger, bill rows, parameter rows, GST summary, the link) and the supplier's bills before answering. Purchase returns, purchases, receipts and sales returns share one lock on the PC.\n\n**Refused before BUSY:** an unknown master (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), a reference already held (`409 PURCHASE_RETURN_REFERENCE_TAKEN`, `details.purchaseReturnId`), a number in the series (`409 PURCHASE_RETURN_NUMBER_TAKEN`), a held new-reference name (`409 PURCHASE_RETURN_NEW_REFERENCE_TAKEN`), more than the original still has (`422 PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE`), an ambiguous original or history (`422 PURCHASE_RETURN_ORIGINAL_AMBIGUOUS` / `PURCHASE_RETURN_HISTORY_AMBIGUOUS`), over-settlement (`422 PURCHASE_RETURN_BILL_OVERSETTLED`), a missing or unwanted adjustment (`422 PURCHASE_RETURN_ADJUSTMENT_REQUIRED` / `_UNSUPPORTED`), an automatic series, other purchase types, tracked items, other bill sundries (`422`), 3 decimals (`400`).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `purchaseReturnReference` of at most 25 characters (current value) before each send — for example `AZPM-PRT-0NN`. This request uses it as the reference, the voucher number and the new debit reference's number. The request is skipped without one. Do not reuse `AZPOC-PRT-…` or `AZSVC-PRT-…` (PoC and acceptance records: suppliers 1364-1367, originals 151-154 and 174-177, returns 155-173 and 178-183).\n- The example body is one local line for the PoC's bill-by-bill test supplier, without an original purchase, its whole total as a new debit reference. To test against an original, add `originalPurchase` and `adjustment.againstOriginalPurchase` with a fresh dedicated test purchase.\n- Nothing is deleted automatically: a created test return stays in BUSY (and moves stock out).\n- **Never retry blindly.** Sending the same `purchaseReturnReference` again is refused (`409 PURCHASE_RETURN_REFERENCE_TAKEN`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `purchaseReturnId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or the supplier's bills differ (`details.purchaseReturnId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC, up to 2 minutes: give the request a long timeout. Body up to 128 KiB.\n\n**Sets:** `purchaseReturnId` on success (usable as `voucherId` with `voucherType` `purchaseReturn` in the Voucher PDF request). Public guide: `docs/public/api/purchase-return-create.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"0f3c9a1d6b2e4c7a9d8e5f1a2b3c4d5e","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"purchaseReturnId\": 8857,\n    \"voucherNumber\": \"DN-2207\",\n    \"returnReference\": \"WEB-PRT-50131\",\n    \"date\": \"2026-10-20\",\n    \"voucherSeries\": { \"code\": 261, \"name\": \"Main\" },\n    \"supplier\": { \"code\": 7101, \"name\": \"Synthetic Supplies\" },\n    \"purchaseType\": { \"code\": 9312, \"name\": \"Local-ItemWise\" },\n    \"taxation\": \"local\",\n    \"materialCenter\": { \"code\": 9501, \"name\": \"Main Store\" },\n    \"originalPurchase\": { \"purchaseId\": 8840, \"supplierInvoiceNumber\": \"SUP-7781\", \"date\": \"2026-10-15\" },\n    \"lines\": [\n      { \"lineNumber\": 1, \"item\": { \"code\": 9401, \"name\": \"Synthetic Item\" }, \"unit\": \"Pcs.\", \"quantity\": 4, \"rate\": 120, \"discountPercent\": 0, \"netRate\": 120, \"taxableAmount\": 480, \"cgst\": 28.8, \"sgst\": 28.8, \"igst\": 0, \"taxAmount\": 57.6, \"amount\": 537.6, \"cost\": 480, \"parameters\": [] },\n      { \"lineNumber\": 2, \"item\": { \"code\": 9402, \"name\": \"Synthetic Colour Item\" }, \"unit\": \"Pcs.\", \"quantity\": 2, \"rate\": 80, \"discountPercent\": 0, \"netRate\": 80, \"taxableAmount\": 160, \"cgst\": 9.6, \"sgst\": 9.6, \"igst\": 0, \"taxAmount\": 19.2, \"amount\": 179.2, \"cost\": 160, \"parameters\": [{ \"value\": \"RED\", \"quantity\": 2, \"amount\": 160 }] }\n    ],\n    \"billSundries\": [\n      { \"lineNumber\": 1, \"billSundry\": { \"code\": 9602, \"name\": \"Freight & Forwarding Charges\" }, \"kind\": \"charge\", \"percent\": null, \"baseAmount\": null, \"amount\": 20, \"effect\": \"add\" },\n      { \"lineNumber\": 2, \"billSundry\": { \"code\": 9604, \"name\": \"Rounded Off (-)\" }, \"kind\": \"roundOff\", \"percent\": null, \"baseAmount\": null, \"amount\": 0.8, \"effect\": \"subtract\" }\n    ],\n    \"totals\": { \"quantity\": 6, \"taxableAmount\": 640, \"cgst\": 38.4, \"sgst\": 38.4, \"igst\": 0, \"taxAmount\": 76.8, \"charges\": 20, \"roundOff\": -0.8, \"purchaseValue\": 640, \"amount\": 736 },\n    \"allocations\": [\n      { \"type\": \"againstOriginalPurchase\", \"number\": \"SUP-7781\", \"amount\": 600, \"outstandingBefore\": 1806, \"outstandingAfter\": 1206, \"dueDate\": \"2026-11-14\" },\n      { \"type\": \"newReference\", \"number\": \"DN-2207\", \"amount\": 136, \"outstandingBefore\": null, \"outstandingAfter\": -136, \"dueDate\": \"2026-10-20\" }\n    ],\n    \"narration\": \"Synthetic return of damaged goods\",\n    \"ledger\": [\n      { \"account\": { \"code\": 7101, \"name\": \"Synthetic Supplies\" }, \"debit\": 736, \"credit\": 0 },\n      { \"account\": { \"code\": 9201, \"name\": \"Synthetic Purchase\" }, \"debit\": 0, \"credit\": 640 },\n      { \"account\": { \"code\": 9221, \"name\": \"Synthetic Freight\" }, \"debit\": 0, \"credit\": 20 },\n      { \"account\": { \"code\": 9231, \"name\": \"Synthetic Round Off\" }, \"debit\": 0.8, \"credit\": 0 },\n      { \"account\": { \"code\": 9213, \"name\": \"Synthetic CGST Input\" }, \"debit\": 0, \"credit\": 38.4 },\n      { \"account\": { \"code\": 9214, \"name\": \"Synthetic SGST Input\" }, \"debit\": 0, \"credit\": 38.4 }\n    ]\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.purchase-returns.create\",\n    \"requestId\": \"0f3c9a1d6b2e4c7a9d8e5f1a2b3c4d5e\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 2,\n    \"verification\": [\"busyReadBack\", \"savedRows\"],\n    \"elapsedMs\": 3105,\n    \"executedAt\": \"2026-10-20T06:30:00+00:00\"\n  }\n}"},{"id":"45e093ee-7fb6-dc94-d103-98950d53aada","name":"409 PURCHASE_RETURN_REFERENCE_TAKEN – a retry after a saved return (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PRT SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100 }\n  ],\n  \"adjustment\": { \"newReference\": { \"number\": \"{{purchaseReturnReference}}\" } },\n  \"narration\": \"Postman test purchase return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-return-create","description":"**Local** · `POST {{baseUrl}}/api/v1/purchase-return-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `voucherNumber`, `supplier`, `purchaseType`, `materialCenter`, `lines`; `adjustment` for a supplier kept bill by bill · **Optional:** `voucherSeries`, `originalPurchase`, `billSundries`, `narration` · operation `busy.purchase-returns.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.purchase-returns.create` (`POST /api/v1/purchase-return-create`) creates one BUSY **purchase return / debit note** through BUSY's own COM component on this PC: the supplier is debited with the total, the purchase and GST input accounts credited, the goods leave `materialCenter` at their cost. **Create only**: it never changes, cancels or deletes a return. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15 (`3ee32d4`); **installed service-account acceptance passed 2026-10-15** (COMP0002 / 2026: six returns against fresh originals saved and verified by SQL and BUSY's own XML, eleven refusals wrote nothing); owner acceptance for customers is separate. **Through the cloud: not available** — the PC is relay-ready (same organization token, write rules), but the AI Zeny cloud has no purchase-return route.\n\n**How it works.**\n- **Two numbers, kept apart:** your `returnReference` (1-60, first narration, unique among the company's purchase returns of the year — the retry key) and your debit-note `voucherNumber` (1-25, new in the purchase-return series; also recorded as the return's own bill number and date). Only a series with **manual** numbering is accepted.\n- `lines` (1-100): positive values — `item`, `quantity` (main unit, **at most 2 decimals**), `rate`, optional `discountPercent` (the rate after discount must have at most 2 decimals — never rounded), `parameters` (required for a parameter-wise item; the purchase's parameter-setup rules). No `mrp` or `description`.\n- `originalPurchase` (optional, `voucherId` or `supplierInvoiceNumber`): the supplier's own live purchase, not later than the return, same local/central kind. Each item and parameter value is then capped at what it bought less earlier live returns naming it; an unattributable history is refused. **Without it there is no quantity ceiling; returns naming no purchase never count; stock is not checked.**\n- For a supplier BUSY keeps bill by bill, `adjustment` must cover the **whole total**: `againstOriginalPurchase` (the original's payable, never over-settled; default the smaller of the total and what it owes) and `newReference` (a new number for the rest, due on the return's date; no due date of its own). Allocations are sent negative. A supplier not kept bill by bill takes no `adjustment`.\n- `billSundries` (optional): fixed charges and one Rounded Off (-) ≤ 0.99. A discount and Rounded Off (+) are refused.\n- No purpose code or billing is sent. AI Zeny compares BUSY's read-back, the saved rows (signs, ledger, bill rows, parameter rows, GST summary, the link) and the supplier's bills before answering. Purchase returns, purchases, receipts and sales returns share one lock on the PC.\n\n**Refused before BUSY:** an unknown master (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), a reference already held (`409 PURCHASE_RETURN_REFERENCE_TAKEN`, `details.purchaseReturnId`), a number in the series (`409 PURCHASE_RETURN_NUMBER_TAKEN`), a held new-reference name (`409 PURCHASE_RETURN_NEW_REFERENCE_TAKEN`), more than the original still has (`422 PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE`), an ambiguous original or history (`422 PURCHASE_RETURN_ORIGINAL_AMBIGUOUS` / `PURCHASE_RETURN_HISTORY_AMBIGUOUS`), over-settlement (`422 PURCHASE_RETURN_BILL_OVERSETTLED`), a missing or unwanted adjustment (`422 PURCHASE_RETURN_ADJUSTMENT_REQUIRED` / `_UNSUPPORTED`), an automatic series, other purchase types, tracked items, other bill sundries (`422`), 3 decimals (`400`).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `purchaseReturnReference` of at most 25 characters (current value) before each send — for example `AZPM-PRT-0NN`. This request uses it as the reference, the voucher number and the new debit reference's number. The request is skipped without one. Do not reuse `AZPOC-PRT-…` or `AZSVC-PRT-…` (PoC and acceptance records: suppliers 1364-1367, originals 151-154 and 174-177, returns 155-173 and 178-183).\n- The example body is one local line for the PoC's bill-by-bill test supplier, without an original purchase, its whole total as a new debit reference. To test against an original, add `originalPurchase` and `adjustment.againstOriginalPurchase` with a fresh dedicated test purchase.\n- Nothing is deleted automatically: a created test return stays in BUSY (and moves stock out).\n- **Never retry blindly.** Sending the same `purchaseReturnReference` again is refused (`409 PURCHASE_RETURN_REFERENCE_TAKEN`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `purchaseReturnId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or the supplier's bills differ (`details.purchaseReturnId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC, up to 2 minutes: give the request a long timeout. Body up to 128 KiB.\n\n**Sets:** `purchaseReturnId` on success (usable as `voucherId` with `voucherType` `purchaseReturn` in the Voucher PDF request). Public guide: `docs/public/api/purchase-return-create.md`."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"1a2b3c4d5e6f40718293a4b5c6d7e8f9"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PURCHASE_RETURN_REFERENCE_TAKEN\",\n      \"message\": \"A purchase return of this company and financial year already holds this returnReference. A create never changes an existing return; if your earlier call saved it, metadata.error.details.purchaseReturnId names it.\",\n      \"field\": \"returnReference\",\n      \"details\": { \"purchaseReturnId\": 8857 }\n    },\n    \"requestId\": \"1a2b3c4d5e6f40718293a4b5c6d7e8f9\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"9697305b-b8ae-c2b3-cebb-b62f69891c1a","name":"422 PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE – more than the original still has (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PRT SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100 }\n  ],\n  \"adjustment\": { \"newReference\": { \"number\": \"{{purchaseReturnReference}}\" } },\n  \"narration\": \"Postman test purchase return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-return-create","description":"**Local** · `POST {{baseUrl}}/api/v1/purchase-return-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `voucherNumber`, `supplier`, `purchaseType`, `materialCenter`, `lines`; `adjustment` for a supplier kept bill by bill · **Optional:** `voucherSeries`, `originalPurchase`, `billSundries`, `narration` · operation `busy.purchase-returns.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.purchase-returns.create` (`POST /api/v1/purchase-return-create`) creates one BUSY **purchase return / debit note** through BUSY's own COM component on this PC: the supplier is debited with the total, the purchase and GST input accounts credited, the goods leave `materialCenter` at their cost. **Create only**: it never changes, cancels or deletes a return. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15 (`3ee32d4`); **installed service-account acceptance passed 2026-10-15** (COMP0002 / 2026: six returns against fresh originals saved and verified by SQL and BUSY's own XML, eleven refusals wrote nothing); owner acceptance for customers is separate. **Through the cloud: not available** — the PC is relay-ready (same organization token, write rules), but the AI Zeny cloud has no purchase-return route.\n\n**How it works.**\n- **Two numbers, kept apart:** your `returnReference` (1-60, first narration, unique among the company's purchase returns of the year — the retry key) and your debit-note `voucherNumber` (1-25, new in the purchase-return series; also recorded as the return's own bill number and date). Only a series with **manual** numbering is accepted.\n- `lines` (1-100): positive values — `item`, `quantity` (main unit, **at most 2 decimals**), `rate`, optional `discountPercent` (the rate after discount must have at most 2 decimals — never rounded), `parameters` (required for a parameter-wise item; the purchase's parameter-setup rules). No `mrp` or `description`.\n- `originalPurchase` (optional, `voucherId` or `supplierInvoiceNumber`): the supplier's own live purchase, not later than the return, same local/central kind. Each item and parameter value is then capped at what it bought less earlier live returns naming it; an unattributable history is refused. **Without it there is no quantity ceiling; returns naming no purchase never count; stock is not checked.**\n- For a supplier BUSY keeps bill by bill, `adjustment` must cover the **whole total**: `againstOriginalPurchase` (the original's payable, never over-settled; default the smaller of the total and what it owes) and `newReference` (a new number for the rest, due on the return's date; no due date of its own). Allocations are sent negative. A supplier not kept bill by bill takes no `adjustment`.\n- `billSundries` (optional): fixed charges and one Rounded Off (-) ≤ 0.99. A discount and Rounded Off (+) are refused.\n- No purpose code or billing is sent. AI Zeny compares BUSY's read-back, the saved rows (signs, ledger, bill rows, parameter rows, GST summary, the link) and the supplier's bills before answering. Purchase returns, purchases, receipts and sales returns share one lock on the PC.\n\n**Refused before BUSY:** an unknown master (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), a reference already held (`409 PURCHASE_RETURN_REFERENCE_TAKEN`, `details.purchaseReturnId`), a number in the series (`409 PURCHASE_RETURN_NUMBER_TAKEN`), a held new-reference name (`409 PURCHASE_RETURN_NEW_REFERENCE_TAKEN`), more than the original still has (`422 PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE`), an ambiguous original or history (`422 PURCHASE_RETURN_ORIGINAL_AMBIGUOUS` / `PURCHASE_RETURN_HISTORY_AMBIGUOUS`), over-settlement (`422 PURCHASE_RETURN_BILL_OVERSETTLED`), a missing or unwanted adjustment (`422 PURCHASE_RETURN_ADJUSTMENT_REQUIRED` / `_UNSUPPORTED`), an automatic series, other purchase types, tracked items, other bill sundries (`422`), 3 decimals (`400`).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `purchaseReturnReference` of at most 25 characters (current value) before each send — for example `AZPM-PRT-0NN`. This request uses it as the reference, the voucher number and the new debit reference's number. The request is skipped without one. Do not reuse `AZPOC-PRT-…` or `AZSVC-PRT-…` (PoC and acceptance records: suppliers 1364-1367, originals 151-154 and 174-177, returns 155-173 and 178-183).\n- The example body is one local line for the PoC's bill-by-bill test supplier, without an original purchase, its whole total as a new debit reference. To test against an original, add `originalPurchase` and `adjustment.againstOriginalPurchase` with a fresh dedicated test purchase.\n- Nothing is deleted automatically: a created test return stays in BUSY (and moves stock out).\n- **Never retry blindly.** Sending the same `purchaseReturnReference` again is refused (`409 PURCHASE_RETURN_REFERENCE_TAKEN`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `purchaseReturnId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or the supplier's bills differ (`details.purchaseReturnId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC, up to 2 minutes: give the request a long timeout. Body up to 128 KiB.\n\n**Sets:** `purchaseReturnId` on success (usable as `voucherId` with `voucherType` `purchaseReturn` in the Voucher PDF request). Public guide: `docs/public/api/purchase-return-create.md`."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"2b3c4d5e6f7041829304b5c6d7e8f9a0"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE\",\n      \"message\": \"This line returns more of the item than the original purchase still has to return (its quantity less the earlier returns that name it).\",\n      \"field\": \"lines[0].quantity\"\n    },\n    \"requestId\": \"2b3c4d5e6f7041829304b5c6d7e8f9a0\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"d83102d4-90aa-66e7-da60-bbf6b881f819","name":"422 PURCHASE_RETURN_BILL_OVERSETTLED – more than the payable owes (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PRT SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100 }\n  ],\n  \"adjustment\": { \"newReference\": { \"number\": \"{{purchaseReturnReference}}\" } },\n  \"narration\": \"Postman test purchase return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-return-create","description":"**Local** · `POST {{baseUrl}}/api/v1/purchase-return-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `voucherNumber`, `supplier`, `purchaseType`, `materialCenter`, `lines`; `adjustment` for a supplier kept bill by bill · **Optional:** `voucherSeries`, `originalPurchase`, `billSundries`, `narration` · operation `busy.purchase-returns.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.purchase-returns.create` (`POST /api/v1/purchase-return-create`) creates one BUSY **purchase return / debit note** through BUSY's own COM component on this PC: the supplier is debited with the total, the purchase and GST input accounts credited, the goods leave `materialCenter` at their cost. **Create only**: it never changes, cancels or deletes a return. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15 (`3ee32d4`); **installed service-account acceptance passed 2026-10-15** (COMP0002 / 2026: six returns against fresh originals saved and verified by SQL and BUSY's own XML, eleven refusals wrote nothing); owner acceptance for customers is separate. **Through the cloud: not available** — the PC is relay-ready (same organization token, write rules), but the AI Zeny cloud has no purchase-return route.\n\n**How it works.**\n- **Two numbers, kept apart:** your `returnReference` (1-60, first narration, unique among the company's purchase returns of the year — the retry key) and your debit-note `voucherNumber` (1-25, new in the purchase-return series; also recorded as the return's own bill number and date). Only a series with **manual** numbering is accepted.\n- `lines` (1-100): positive values — `item`, `quantity` (main unit, **at most 2 decimals**), `rate`, optional `discountPercent` (the rate after discount must have at most 2 decimals — never rounded), `parameters` (required for a parameter-wise item; the purchase's parameter-setup rules). No `mrp` or `description`.\n- `originalPurchase` (optional, `voucherId` or `supplierInvoiceNumber`): the supplier's own live purchase, not later than the return, same local/central kind. Each item and parameter value is then capped at what it bought less earlier live returns naming it; an unattributable history is refused. **Without it there is no quantity ceiling; returns naming no purchase never count; stock is not checked.**\n- For a supplier BUSY keeps bill by bill, `adjustment` must cover the **whole total**: `againstOriginalPurchase` (the original's payable, never over-settled; default the smaller of the total and what it owes) and `newReference` (a new number for the rest, due on the return's date; no due date of its own). Allocations are sent negative. A supplier not kept bill by bill takes no `adjustment`.\n- `billSundries` (optional): fixed charges and one Rounded Off (-) ≤ 0.99. A discount and Rounded Off (+) are refused.\n- No purpose code or billing is sent. AI Zeny compares BUSY's read-back, the saved rows (signs, ledger, bill rows, parameter rows, GST summary, the link) and the supplier's bills before answering. Purchase returns, purchases, receipts and sales returns share one lock on the PC.\n\n**Refused before BUSY:** an unknown master (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), a reference already held (`409 PURCHASE_RETURN_REFERENCE_TAKEN`, `details.purchaseReturnId`), a number in the series (`409 PURCHASE_RETURN_NUMBER_TAKEN`), a held new-reference name (`409 PURCHASE_RETURN_NEW_REFERENCE_TAKEN`), more than the original still has (`422 PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE`), an ambiguous original or history (`422 PURCHASE_RETURN_ORIGINAL_AMBIGUOUS` / `PURCHASE_RETURN_HISTORY_AMBIGUOUS`), over-settlement (`422 PURCHASE_RETURN_BILL_OVERSETTLED`), a missing or unwanted adjustment (`422 PURCHASE_RETURN_ADJUSTMENT_REQUIRED` / `_UNSUPPORTED`), an automatic series, other purchase types, tracked items, other bill sundries (`422`), 3 decimals (`400`).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `purchaseReturnReference` of at most 25 characters (current value) before each send — for example `AZPM-PRT-0NN`. This request uses it as the reference, the voucher number and the new debit reference's number. The request is skipped without one. Do not reuse `AZPOC-PRT-…` or `AZSVC-PRT-…` (PoC and acceptance records: suppliers 1364-1367, originals 151-154 and 174-177, returns 155-173 and 178-183).\n- The example body is one local line for the PoC's bill-by-bill test supplier, without an original purchase, its whole total as a new debit reference. To test against an original, add `originalPurchase` and `adjustment.againstOriginalPurchase` with a fresh dedicated test purchase.\n- Nothing is deleted automatically: a created test return stays in BUSY (and moves stock out).\n- **Never retry blindly.** Sending the same `purchaseReturnReference` again is refused (`409 PURCHASE_RETURN_REFERENCE_TAKEN`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `purchaseReturnId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or the supplier's bills differ (`details.purchaseReturnId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC, up to 2 minutes: give the request a long timeout. Body up to 128 KiB.\n\n**Sets:** `purchaseReturnId` on success (usable as `voucherId` with `voucherType` `purchaseReturn` in the Voucher PDF request). Public guide: `docs/public/api/purchase-return-create.md`."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"3c4d5e6f708142939415c6d7e8f9a0b1","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PURCHASE_RETURN_BILL_OVERSETTLED\",\n      \"message\": \"adjustment.againstOriginalPurchase.amount is more than the original purchase's payable still owes. Send at most the outstanding amount and the rest as newReference.\",\n      \"field\": \"adjustment.againstOriginalPurchase.amount\"\n    },\n    \"requestId\": \"3c4d5e6f708142939415c6d7e8f9a0b1\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"f18add57-fbd3-5c8e-4ad0-a02650c94502","name":"504 BUSY_WRITE_UNCERTAIN – reconciled found, never resend (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PRT SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100 }\n  ],\n  \"adjustment\": { \"newReference\": { \"number\": \"{{purchaseReturnReference}}\" } },\n  \"narration\": \"Postman test purchase return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-return-create","description":"**Local** · `POST {{baseUrl}}/api/v1/purchase-return-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`)\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `voucherNumber`, `supplier`, `purchaseType`, `materialCenter`, `lines`; `adjustment` for a supplier kept bill by bill · **Optional:** `voucherSeries`, `originalPurchase`, `billSundries`, `narration` · operation `busy.purchase-returns.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.purchase-returns.create` (`POST /api/v1/purchase-return-create`) creates one BUSY **purchase return / debit note** through BUSY's own COM component on this PC: the supplier is debited with the total, the purchase and GST input accounts credited, the goods leave `materialCenter` at their cost. **Create only**: it never changes, cancels or deletes a return. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15 (`3ee32d4`); **installed service-account acceptance passed 2026-10-15** (COMP0002 / 2026: six returns against fresh originals saved and verified by SQL and BUSY's own XML, eleven refusals wrote nothing); owner acceptance for customers is separate. **Through the cloud: not available** — the PC is relay-ready (same organization token, write rules), but the AI Zeny cloud has no purchase-return route.\n\n**How it works.**\n- **Two numbers, kept apart:** your `returnReference` (1-60, first narration, unique among the company's purchase returns of the year — the retry key) and your debit-note `voucherNumber` (1-25, new in the purchase-return series; also recorded as the return's own bill number and date). Only a series with **manual** numbering is accepted.\n- `lines` (1-100): positive values — `item`, `quantity` (main unit, **at most 2 decimals**), `rate`, optional `discountPercent` (the rate after discount must have at most 2 decimals — never rounded), `parameters` (required for a parameter-wise item; the purchase's parameter-setup rules). No `mrp` or `description`.\n- `originalPurchase` (optional, `voucherId` or `supplierInvoiceNumber`): the supplier's own live purchase, not later than the return, same local/central kind. Each item and parameter value is then capped at what it bought less earlier live returns naming it; an unattributable history is refused. **Without it there is no quantity ceiling; returns naming no purchase never count; stock is not checked.**\n- For a supplier BUSY keeps bill by bill, `adjustment` must cover the **whole total**: `againstOriginalPurchase` (the original's payable, never over-settled; default the smaller of the total and what it owes) and `newReference` (a new number for the rest, due on the return's date; no due date of its own). Allocations are sent negative. A supplier not kept bill by bill takes no `adjustment`.\n- `billSundries` (optional): fixed charges and one Rounded Off (-) ≤ 0.99. A discount and Rounded Off (+) are refused.\n- No purpose code or billing is sent. AI Zeny compares BUSY's read-back, the saved rows (signs, ledger, bill rows, parameter rows, GST summary, the link) and the supplier's bills before answering. Purchase returns, purchases, receipts and sales returns share one lock on the PC.\n\n**Refused before BUSY:** an unknown master (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), a reference already held (`409 PURCHASE_RETURN_REFERENCE_TAKEN`, `details.purchaseReturnId`), a number in the series (`409 PURCHASE_RETURN_NUMBER_TAKEN`), a held new-reference name (`409 PURCHASE_RETURN_NEW_REFERENCE_TAKEN`), more than the original still has (`422 PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE`), an ambiguous original or history (`422 PURCHASE_RETURN_ORIGINAL_AMBIGUOUS` / `PURCHASE_RETURN_HISTORY_AMBIGUOUS`), over-settlement (`422 PURCHASE_RETURN_BILL_OVERSETTLED`), a missing or unwanted adjustment (`422 PURCHASE_RETURN_ADJUSTMENT_REQUIRED` / `_UNSUPPORTED`), an automatic series, other purchase types, tracked items, other bill sundries (`422`), 3 decimals (`400`).\n\n**Safe test guidance**\n- Use only the **development-test company** (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) and set a **new, unique** `purchaseReturnReference` of at most 25 characters (current value) before each send — for example `AZPM-PRT-0NN`. This request uses it as the reference, the voucher number and the new debit reference's number. The request is skipped without one. Do not reuse `AZPOC-PRT-…` or `AZSVC-PRT-…` (PoC and acceptance records: suppliers 1364-1367, originals 151-154 and 174-177, returns 155-173 and 178-183).\n- The example body is one local line for the PoC's bill-by-bill test supplier, without an original purchase, its whole total as a new debit reference. To test against an original, add `originalPurchase` and `adjustment.againstOriginalPurchase` with a fresh dedicated test purchase.\n- Nothing is deleted automatically: a created test return stays in BUSY (and moves stock out).\n- **Never retry blindly.** Sending the same `purchaseReturnReference` again is refused (`409 PURCHASE_RETURN_REFERENCE_TAKEN`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `purchaseReturnId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or the supplier's bills differ (`details.purchaseReturnId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC, up to 2 minutes: give the request a long timeout. Body up to 128 KiB.\n\n**Sets:** `purchaseReturnId` on success (usable as `voucherId` with `voucherType` `purchaseReturn` in the Voucher PDF request). Public guide: `docs/public/api/purchase-return-create.md`."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"4d5e6f70819243a4a526d7e8f9a0b1c2","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"BUSY stopped while saving the purchase return; a return with this returnReference exists now (metadata.error.details.purchaseReturnId). Check it in BUSY; do not send it again.\",\n      \"details\": { \"purchaseReturnId\": 8857, \"reconciliation\": \"found\" }\n    },\n    \"requestId\": \"4d5e6f70819243a4a526d7e8f9a0b1c2\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"651c5091-fef7-57bc-20b6-fe39c46883d5","name":"409 – GST_CONFIGURATION_CHANGED (before save)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PRT SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic 5% item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0,\n        \"amount\": 13.26\n      }\n    }\n  ],\n  \"adjustment\": {\n    \"newReference\": {\n      \"number\": \"{{purchaseReturnReference}}\"\n    }\n  },\n  \"narration\": \"Postman test purchase return\",\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0,\n    \"amount\": 13.26\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-return-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"GST_CONFIGURATION_CHANGED\",\n      \"message\": \"BUSY's selected GST or voucher-series configuration changed while this request was being prepared. Read it again and submit a new request.\"\n    }\n  }\n}"},{"id":"1f98c990-3a8f-4c16-9993-bef879565418","name":"422 – GST_AMOUNTS_INVALID (manual treatment)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PRT SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic 5% item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0.05,\n        \"amount\": 13.31\n      }\n    }\n  ],\n  \"adjustment\": {\n    \"newReference\": {\n      \"number\": \"{{purchaseReturnReference}}\"\n    }\n  },\n  \"narration\": \"Postman test purchase return\",\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0.05,\n    \"amount\": 13.31\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-return-create"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"GST_AMOUNTS_INVALID\",\n      \"message\": \"Manual GST amounts conflict with the selected tax rate or local/central treatment.\"\n    }\n  }\n}"},{"id":"fbd91a6c-44a2-1240-0f44-01b3b1f61c25","name":"502 – BUSY_WRITE_UNVERIFIED (saved; reconcile)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PRT SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic 5% item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 10.1,\n      \"amounts\": {\n        \"taxableAmount\": 12.62,\n        \"cgst\": 0.32,\n        \"sgst\": 0.32,\n        \"igst\": 0,\n        \"amount\": 13.26\n      }\n    }\n  ],\n  \"adjustment\": {\n    \"newReference\": {\n      \"number\": \"{{purchaseReturnReference}}\"\n    }\n  },\n  \"narration\": \"Postman test purchase return\",\n  \"totals\": {\n    \"taxableAmount\": 12.62,\n    \"cgst\": 0.32,\n    \"sgst\": 0.32,\n    \"igst\": 0,\n    \"amount\": 13.26\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-return-create"},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNVERIFIED\",\n      \"message\": \"BUSY saved the voucher but read-back differs; inspect the saved reference and do not resend.\"\n    }\n  }\n}"},{"id":"6049f563-78ce-e18e-6871-e24bb1a51927","name":"400 – INVALID_PARAMETER (Manual breakdown missing)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PRT SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100\n    }\n  ],\n  \"adjustment\": {\n    \"newReference\": {\n      \"number\": \"{{purchaseReturnReference}}\"\n    }\n  },\n  \"narration\": \"Postman test purchase return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-return-create"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"Manual GST breakdown is required for every line and document totals.\"\n    }\n  }\n}"},{"id":"ad6b5af0-78e0-56ef-206d-4e02fe06d0f3","name":"422 – GST_MODE_UNSUPPORTED (Purchase Return bill allocation)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstInclusive\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PRT SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100\n    }\n  ],\n  \"adjustment\": {\n    \"newReference\": {\n      \"number\": \"{{purchaseReturnReference}}\"\n    }\n  },\n  \"narration\": \"Postman test purchase return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-return-create"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"GST_MODE_UNSUPPORTED\",\n      \"message\": \"This new GST mode and linked/allocated/sundry combination requires separate native proof.\",\n      \"field\": \"originalPurchase\"\n    }\n  }\n}"},{"id":"04f2c145-a336-ec07-2816-ee76794016de","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"{{writeRequestId}}","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PRT SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100\n    }\n  ],\n  \"adjustment\": {\n    \"newReference\": {\n      \"number\": \"{{purchaseReturnReference}}\"\n    }\n  },\n  \"narration\": \"Postman test purchase return\",\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-return-create"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"synthetic-queue-001"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.purchase-returns.create\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"}],"_postman_id":"09a72907-d91c-8710-d15d-83c0288e9fe9"},{"name":"⚠ BUSY payment – create (writes to BUSY)","id":"189dceb0-dad7-46b9-d68f-8c73d267f2e9","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"payee\": { \"name\": \"AZPM-PAY PAYEE\" },\n  \"amount\": 10,\n  \"allocations\": [\n    { \"newReference\": { \"number\": \"{{paymentReference}}\" }, \"amount\": 10 }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/payment-create","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/payment-create</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>⚠ Writes to BUSY</strong> (Development Local Send requires no separate confirmation)\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>paymentReference</code>, <code>date</code>, <code>account</code>, <code>payee</code>, <code>amount</code> · <strong>Optional:</strong> <code>voucherNumber</code>, <code>voucherSeries</code>, <code>allocations</code>, <code>instrumentNumber</code>, <code>shortNarration</code>, <code>narration</code> · operation <code>busy.payments.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<p><strong>Access companies (2026-10-18):</strong> runs on SQL Server companies with a SQL login <strong>and</strong> on BUSY companies kept in Access files (opened with BUSY's <code>OpenDBForYear</code> and the data folder; no SQL sign-in). Implemented 2026-10-18 (<code>5676376</code>); <strong>installed service-account acceptance on Access passed 2026-10-19</strong> (installed Host as <code>.\\AIZenySvc</code>, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (<code>docs/LOCAL-API.md</code> 5aq).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books. Run manually, one at a time.</strong> <code>busy.payments.create</code> (<code>POST /api/v1/payment-create</code>) records one BUSY <strong>payment voucher</strong> through BUSY's own COM component on this PC: the cash, bank or bank OD <code>account</code> is credited and the <code>payee</code> debited. <strong>It is an accounting entry only: no bank transfer, cheque or payment instruction is ever made.</strong> <strong>Create only</strong>: it never changes, cancels or deletes a payment. <strong>SQL Server companies with a SQL login, or Access companies</strong>. Never run from scripts. <strong>Status:</strong> implemented 2026-10-15; <strong>installed service-account acceptance passed 2026-10-16</strong> (COMP0002 / 2026, payments 216-223, overdrawn Cash and Bank included). <strong>Through the cloud: not available</strong> — the PC is relay-ready (same organization token, write rules, <code>details.paymentId</code>), but the AI Zeny cloud has no payment route.</p>\n<p><strong>How it works.</strong></p>\n<ul>\n<li><strong>Numbers:</strong> your <code>paymentReference</code> (1-60, first narration, unique among the company's payments of the year — the retry key) and the voucher number in a <strong>manually numbered</strong> payment series: <code>voucherNumber</code> (1-25), or by default your <code>paymentReference</code> when it fits 25 characters. Never an empty number; it must be new in the series (<code>409 PAYMENT_NUMBER_TAKEN</code>). An automatically numbered series is refused (<code>422 PAYMENT_SERIES_UNSUPPORTED</code>).</li>\n<li><code>allocations</code> (optional, 1-100, only for a payee kept bill by bill): <code>bill</code> (one the payee is still owed, at most its outstanding) or <code>newReference</code> (an advance, a number new to the payee; due on the payment date unless <code>dueDate</code>). <strong>Amounts are positive</strong>; AI Zeny records them as debits, as BUSY does. The rest stays on account (<code>unallocatedAmount</code>).</li>\n<li><code>instrumentNumber</code> and <code>shortNarration</code> go on the payee's line; an instrument type is not accepted.</li>\n<li><strong>Never refused for an insufficient balance</strong> (owner decision PY-10): a payment may leave Cash, Bank or Bank OD negative, as in BUSY. <code>data.accountBalanceAfter</code> = <code>{ asOfDate, balance, side }</code>: the paying account's balance at the <strong>end of the payment date</strong> (<code>asOfDate</code>) — its opening plus every non-cancelled, non-opening voucher dated on or before that day, this payment included; <code>balance</code> <strong>positive = funds held (debit), negative = overdrawn (credit)</strong>; <code>side</code> <code>debit</code> / <code>credit</code> / <code>nil</code>. Read from BUSY after the save.</li>\n<li>AI Zeny compares BUSY's read-back, the saved rows (signs, <code>CashFlow</code>, bill rows) and each settled bill's outstanding before answering. Payments, receipts, sales returns, purchases and purchase returns share one lock on the PC.</li>\n</ul>\n<p><strong>Refused before BUSY:</strong> an unknown master (<code>422 MASTER_REFERENCE_NOT_FOUND</code>; BUSY would create it), a reference already held (<code>409 PAYMENT_REFERENCE_TAKEN</code>, <code>details.paymentId</code>), a held number (<code>409 PAYMENT_NUMBER_TAKEN</code>), a held new-reference name (<code>409 PAYMENT_NEW_REFERENCE_TAKEN</code>), a bill the payee is not owed (<code>422 PAYMENT_BILL_NOT_FOUND</code>), over-settlement (<code>422 PAYMENT_BILL_OVERSETTLED</code>), allocations for a payee not kept bill by bill (<code>422 PAYMENT_ALLOCATION_UNSUPPORTED</code>), a non-cash/bank account or a cash/bank payee (<code>422 PAYMENT_ACCOUNT_UNSUPPORTED</code>), an automatic series (<code>422</code>), 3 decimals or allocations above the amount (<code>400</code>).</p>\n<p><strong>Safe test guidance</strong></p>\n<ul>\n<li>Select a development-test <code>companyCode</code> (<code>COMP0002</code> / FY 2026 in this environment; use <code>COMP0001</code> for Access tests). With <code>autoVoucherReferences=yes</code>, each Local Send generates and stores a fresh 25-character synthetic <code>paymentReference</code>. Set that switch to <code>no</code> to supply your own unique reference. The reference is also the default voucher number and advance number.</li>\n<li><strong>Replace the example payee <code>AZPM-PAY PAYEE</code></strong> (it does not exist, so the example is refused with <code>422 MASTER_REFERENCE_NOT_FOUND</code> and nothing is written) with a <strong>fresh dedicated test account</strong> kept bill by bill. Do not use the PoC's or acceptance's records (<code>AZPOC-PAY …</code>, <code>AZSVC-PAY …</code>, accounts 1368-1373, payments 191-209 and 216-223) and do not settle their bills.</li>\n<li>COMP0002's Cash and ICICI Bank are in credit (overdrawn) after the PoC and the acceptance: expect a negative <code>accountBalanceAfter</code>; the payment is still made.</li>\n<li>Nothing is deleted automatically: a created test payment stays in BUSY.</li>\n<li><strong>Never retry blindly.</strong> Automatic references change on each Send, so another Send can create another voucher; reconcile an uncertain result first. Sending the same <code>paymentReference</code> again is refused (<code>409 PAYMENT_REFERENCE_TAKEN</code>) if the first send saved. After <code>504 BUSY_WRITE_UNCERTAIN</code>, read <code>metadata.error.details.reconciliation</code> (<code>found</code> + <code>paymentId</code>, <code>notFound</code>, <code>notChecked</code>) and check BUSY first.</li>\n<li><code>502 BUSY_WRITE_UNVERIFIED</code> means BUSY <strong>did</strong> save but its read-back, saved rows or a settled bill differ (<code>details.paymentId</code>, <code>details.mismatchedFields</code>).</li>\n<li>One BUSY job at a time on the PC, up to 2 minutes: give the request a long timeout. Body up to 64 KiB.</li>\n</ul>\n<p><strong>Sets:</strong> <code>paymentId</code> on success (usable as <code>voucherId</code> with <code>voucherType</code> <code>payment</code> in the Voucher PDF request). Public guide: <code>docs/public/api/payment-create.md</code>.</p>\n<h2 id=\"optional-durable-write-queue-windows-local-api-source\">Optional durable write queue (Windows Local API source)</h2>\n<p><code>queue</code> is an optional strict boolean at the voucher/master request root. Omit it or send <code>false</code> for the existing synchronous flow and its normal response. Add <code>\"queue\": true</code> to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with <code>GET /api/v1/write-jobs/{id}</code> or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.</p>\n<p>Optional <code>X-Request-Id</code>: 1–128 ASCII letters/digits plus <code>. _ : -</code>. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>. <code>503 WRITE_QUEUE_UNAVAILABLE</code> refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.</p>\n<p>Postman includes a disabled <code>X-Request-Id: {{writeRequestId}}</code> header on this request. Set <code>writeRequestId</code> to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Installed public v0.0.30 predates this merged source; these are documentation examples only. Do not Send until a newer candidate with this source is installed and the target BUSY series is verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"account\": {\n    \"name\": \"Cash\"\n  },\n  \"payee\": {\n    \"name\": \"AZPM-PAY PAYEE\"\n  },\n  \"amount\": 10,\n  \"allocations\": [\n    {\n      \"newReference\": {\n        \"number\": \"{{paymentReference}}\"\n      },\n      \"amount\": 10\n    }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\",\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"account\": {\n    \"name\": \"Cash\"\n  },\n  \"payee\": {\n    \"name\": \"AZPM-PAY PAYEE\"\n  },\n  \"amount\": 10,\n  \"allocations\": [\n    {\n      \"newReference\": {\n        \"number\": \"{{paymentReference}}\"\n      },\n      \"amount\": 10\n    }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\",\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","payment-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"22909eb0-6c49-3467-2520-3fa3dcdabee4","name":"200 — created (two bills, an advance, the rest on account; the bank left overdrawn and still paid, PY-10; synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"payee\": { \"name\": \"AZPM-PAY PAYEE\" },\n  \"amount\": 10,\n  \"allocations\": [\n    { \"newReference\": { \"number\": \"{{paymentReference}}\" }, \"amount\": 10 }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/payment-create","description":"**Local** · `POST {{baseUrl}}/api/v1/payment-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (Development Local Send requires no separate confirmation)\n**Required:** `companyCode`, `financialYear`, `paymentReference`, `date`, `account`, `payee`, `amount` · **Optional:** `voucherNumber`, `voucherSeries`, `allocations`, `instrumentNumber`, `shortNarration`, `narration` · operation `busy.payments.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.payments.create` (`POST /api/v1/payment-create`) records one BUSY **payment voucher** through BUSY's own COM component on this PC: the cash, bank or bank OD `account` is credited and the `payee` debited. **It is an accounting entry only: no bank transfer, cheque or payment instruction is ever made.** **Create only**: it never changes, cancels or deletes a payment. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15; **installed service-account acceptance passed 2026-10-16** (COMP0002 / 2026, payments 216-223, overdrawn Cash and Bank included). **Through the cloud: not available** — the PC is relay-ready (same organization token, write rules, `details.paymentId`), but the AI Zeny cloud has no payment route.\n\n**How it works.**\n- **Numbers:** your `paymentReference` (1-60, first narration, unique among the company's payments of the year — the retry key) and the voucher number in a **manually numbered** payment series: `voucherNumber` (1-25), or by default your `paymentReference` when it fits 25 characters. Never an empty number; it must be new in the series (`409 PAYMENT_NUMBER_TAKEN`). An automatically numbered series is refused (`422 PAYMENT_SERIES_UNSUPPORTED`).\n- `allocations` (optional, 1-100, only for a payee kept bill by bill): `bill` (one the payee is still owed, at most its outstanding) or `newReference` (an advance, a number new to the payee; due on the payment date unless `dueDate`). **Amounts are positive**; AI Zeny records them as debits, as BUSY does. The rest stays on account (`unallocatedAmount`).\n- `instrumentNumber` and `shortNarration` go on the payee's line; an instrument type is not accepted.\n- **Never refused for an insufficient balance** (owner decision PY-10): a payment may leave Cash, Bank or Bank OD negative, as in BUSY. `data.accountBalanceAfter` = `{ asOfDate, balance, side }`: the paying account's balance at the **end of the payment date** (`asOfDate`) — its opening plus every non-cancelled, non-opening voucher dated on or before that day, this payment included; `balance` **positive = funds held (debit), negative = overdrawn (credit)**; `side` `debit` / `credit` / `nil`. Read from BUSY after the save.\n- AI Zeny compares BUSY's read-back, the saved rows (signs, `CashFlow`, bill rows) and each settled bill's outstanding before answering. Payments, receipts, sales returns, purchases and purchase returns share one lock on the PC.\n\n**Refused before BUSY:** an unknown master (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), a reference already held (`409 PAYMENT_REFERENCE_TAKEN`, `details.paymentId`), a held number (`409 PAYMENT_NUMBER_TAKEN`), a held new-reference name (`409 PAYMENT_NEW_REFERENCE_TAKEN`), a bill the payee is not owed (`422 PAYMENT_BILL_NOT_FOUND`), over-settlement (`422 PAYMENT_BILL_OVERSETTLED`), allocations for a payee not kept bill by bill (`422 PAYMENT_ALLOCATION_UNSUPPORTED`), a non-cash/bank account or a cash/bank payee (`422 PAYMENT_ACCOUNT_UNSUPPORTED`), an automatic series (`422`), 3 decimals or allocations above the amount (`400`).\n\n**Safe test guidance**\n- Select a development-test `companyCode` (`COMP0002` / FY 2026 in this environment; use `COMP0001` for Access tests). With `autoVoucherReferences=yes`, each Local Send generates and stores a fresh 25-character synthetic `paymentReference`. Set that switch to `no` to supply your own unique reference. The reference is also the default voucher number and advance number.\n- **Replace the example payee `AZPM-PAY PAYEE`** (it does not exist, so the example is refused with `422 MASTER_REFERENCE_NOT_FOUND` and nothing is written) with a **fresh dedicated test account** kept bill by bill. Do not use the PoC's or acceptance's records (`AZPOC-PAY …`, `AZSVC-PAY …`, accounts 1368-1373, payments 191-209 and 216-223) and do not settle their bills.\n- COMP0002's Cash and ICICI Bank are in credit (overdrawn) after the PoC and the acceptance: expect a negative `accountBalanceAfter`; the payment is still made.\n- Nothing is deleted automatically: a created test payment stays in BUSY.\n- **Never retry blindly.** Automatic references change on each Send, so another Send can create another voucher; reconcile an uncertain result first. Sending the same `paymentReference` again is refused (`409 PAYMENT_REFERENCE_TAKEN`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `paymentId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or a settled bill differ (`details.paymentId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC, up to 2 minutes: give the request a long timeout. Body up to 64 KiB.\n\n**Sets:** `paymentId` on success (usable as `voucherId` with `voucherType` `payment` in the Voucher PDF request). Public guide: `docs/public/api/payment-create.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"paymentId\": 8930,\n    \"voucherNumber\": \"PV-40211\",\n    \"paymentReference\": \"ERP-PAY-40211\",\n    \"date\": \"2026-10-15\",\n    \"voucherSeries\": { \"code\": 268, \"name\": \"Main\" },\n    \"account\": { \"code\": 9001, \"name\": \"Synthetic Bank\" },\n    \"payee\": { \"code\": 7101, \"name\": \"Synthetic Supplies\" },\n    \"amount\": 2000,\n    \"allocations\": [\n      { \"type\": \"bill\", \"number\": \"SUP-1180\", \"amount\": 1180, \"dueDate\": \"2026-10-30\", \"outstandingBefore\": 1180, \"outstandingAfter\": 0 },\n      { \"type\": \"bill\", \"number\": \"SUP-1205\", \"amount\": 500, \"dueDate\": \"2026-11-04\", \"outstandingBefore\": 1205, \"outstandingAfter\": 705 },\n      { \"type\": \"newReference\", \"number\": \"ADV-40211\", \"amount\": 250, \"dueDate\": \"2026-11-30\", \"outstandingBefore\": null, \"outstandingAfter\": null }\n    ],\n    \"allocatedAmount\": 1930,\n    \"unallocatedAmount\": 70,\n    \"instrumentNumber\": \"SYNCHQ000451\",\n    \"shortNarration\": \"Synthetic cheque\",\n    \"narration\": \"Synthetic supplier payment\",\n    \"ledger\": [\n      { \"account\": { \"code\": 7101, \"name\": \"Synthetic Supplies\" }, \"debit\": 2000, \"credit\": 0 },\n      { \"account\": { \"code\": 9001, \"name\": \"Synthetic Bank\" }, \"debit\": 0, \"credit\": 2000 }\n    ],\n    \"accountBalanceAfter\": { \"asOfDate\": \"2026-10-15\", \"balance\": -350.75, \"side\": \"credit\" }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.payments.create\",\n    \"requestId\": \"rq_SYNTHETIC0000000000000001\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"voucherNumberSource\": \"sent\",\n    \"allocationCount\": 3,\n    \"verification\": [\"busyReadBack\", \"savedRows\", \"settledBills\"],\n    \"elapsedMs\": 2280,\n    \"executedAt\": \"2026-10-15T10:30:00+00:00\"\n  }\n}"},{"id":"710b987b-66f2-f1f1-9778-9a94abef671a","name":"409 — PAYMENT_REFERENCE_TAKEN (a retry after a saved payment; synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"payee\": { \"name\": \"AZPM-PAY PAYEE\" },\n  \"amount\": 10,\n  \"allocations\": [\n    { \"newReference\": { \"number\": \"{{paymentReference}}\" }, \"amount\": 10 }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/payment-create","description":"**Local** · `POST {{baseUrl}}/api/v1/payment-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (Development Local Send requires no separate confirmation)\n**Required:** `companyCode`, `financialYear`, `paymentReference`, `date`, `account`, `payee`, `amount` · **Optional:** `voucherNumber`, `voucherSeries`, `allocations`, `instrumentNumber`, `shortNarration`, `narration` · operation `busy.payments.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.payments.create` (`POST /api/v1/payment-create`) records one BUSY **payment voucher** through BUSY's own COM component on this PC: the cash, bank or bank OD `account` is credited and the `payee` debited. **It is an accounting entry only: no bank transfer, cheque or payment instruction is ever made.** **Create only**: it never changes, cancels or deletes a payment. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15; **installed service-account acceptance passed 2026-10-16** (COMP0002 / 2026, payments 216-223, overdrawn Cash and Bank included). **Through the cloud: not available** — the PC is relay-ready (same organization token, write rules, `details.paymentId`), but the AI Zeny cloud has no payment route.\n\n**How it works.**\n- **Numbers:** your `paymentReference` (1-60, first narration, unique among the company's payments of the year — the retry key) and the voucher number in a **manually numbered** payment series: `voucherNumber` (1-25), or by default your `paymentReference` when it fits 25 characters. Never an empty number; it must be new in the series (`409 PAYMENT_NUMBER_TAKEN`). An automatically numbered series is refused (`422 PAYMENT_SERIES_UNSUPPORTED`).\n- `allocations` (optional, 1-100, only for a payee kept bill by bill): `bill` (one the payee is still owed, at most its outstanding) or `newReference` (an advance, a number new to the payee; due on the payment date unless `dueDate`). **Amounts are positive**; AI Zeny records them as debits, as BUSY does. The rest stays on account (`unallocatedAmount`).\n- `instrumentNumber` and `shortNarration` go on the payee's line; an instrument type is not accepted.\n- **Never refused for an insufficient balance** (owner decision PY-10): a payment may leave Cash, Bank or Bank OD negative, as in BUSY. `data.accountBalanceAfter` = `{ asOfDate, balance, side }`: the paying account's balance at the **end of the payment date** (`asOfDate`) — its opening plus every non-cancelled, non-opening voucher dated on or before that day, this payment included; `balance` **positive = funds held (debit), negative = overdrawn (credit)**; `side` `debit` / `credit` / `nil`. Read from BUSY after the save.\n- AI Zeny compares BUSY's read-back, the saved rows (signs, `CashFlow`, bill rows) and each settled bill's outstanding before answering. Payments, receipts, sales returns, purchases and purchase returns share one lock on the PC.\n\n**Refused before BUSY:** an unknown master (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), a reference already held (`409 PAYMENT_REFERENCE_TAKEN`, `details.paymentId`), a held number (`409 PAYMENT_NUMBER_TAKEN`), a held new-reference name (`409 PAYMENT_NEW_REFERENCE_TAKEN`), a bill the payee is not owed (`422 PAYMENT_BILL_NOT_FOUND`), over-settlement (`422 PAYMENT_BILL_OVERSETTLED`), allocations for a payee not kept bill by bill (`422 PAYMENT_ALLOCATION_UNSUPPORTED`), a non-cash/bank account or a cash/bank payee (`422 PAYMENT_ACCOUNT_UNSUPPORTED`), an automatic series (`422`), 3 decimals or allocations above the amount (`400`).\n\n**Safe test guidance**\n- Select a development-test `companyCode` (`COMP0002` / FY 2026 in this environment; use `COMP0001` for Access tests). With `autoVoucherReferences=yes`, each Local Send generates and stores a fresh 25-character synthetic `paymentReference`. Set that switch to `no` to supply your own unique reference. The reference is also the default voucher number and advance number.\n- **Replace the example payee `AZPM-PAY PAYEE`** (it does not exist, so the example is refused with `422 MASTER_REFERENCE_NOT_FOUND` and nothing is written) with a **fresh dedicated test account** kept bill by bill. Do not use the PoC's or acceptance's records (`AZPOC-PAY …`, `AZSVC-PAY …`, accounts 1368-1373, payments 191-209 and 216-223) and do not settle their bills.\n- COMP0002's Cash and ICICI Bank are in credit (overdrawn) after the PoC and the acceptance: expect a negative `accountBalanceAfter`; the payment is still made.\n- Nothing is deleted automatically: a created test payment stays in BUSY.\n- **Never retry blindly.** Automatic references change on each Send, so another Send can create another voucher; reconcile an uncertain result first. Sending the same `paymentReference` again is refused (`409 PAYMENT_REFERENCE_TAKEN`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `paymentId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or a settled bill differ (`details.paymentId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC, up to 2 minutes: give the request a long timeout. Body up to 64 KiB.\n\n**Sets:** `paymentId` on success (usable as `voucherId` with `voucherType` `payment` in the Voucher PDF request). Public guide: `docs/public/api/payment-create.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PAYMENT_REFERENCE_TAKEN\",\n      \"message\": \"A payment of this company and financial year already holds this paymentReference. A create never changes an existing payment; if your earlier call saved it, metadata.error.details.paymentId names it.\",\n      \"field\": \"paymentReference\",\n      \"details\": { \"paymentId\": 8930 }\n    },\n    \"requestId\": \"rq_SYNTHETIC0000000000000002\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"28a41f23-f53b-b493-e747-5eefa6542353","name":"422 — PAYMENT_BILL_NOT_FOUND (not a bill the payee is owed; synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"payee\": { \"name\": \"AZPM-PAY PAYEE\" },\n  \"amount\": 10,\n  \"allocations\": [\n    { \"newReference\": { \"number\": \"{{paymentReference}}\" }, \"amount\": 10 }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/payment-create","description":"**Local** · `POST {{baseUrl}}/api/v1/payment-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (Development Local Send requires no separate confirmation)\n**Required:** `companyCode`, `financialYear`, `paymentReference`, `date`, `account`, `payee`, `amount` · **Optional:** `voucherNumber`, `voucherSeries`, `allocations`, `instrumentNumber`, `shortNarration`, `narration` · operation `busy.payments.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.payments.create` (`POST /api/v1/payment-create`) records one BUSY **payment voucher** through BUSY's own COM component on this PC: the cash, bank or bank OD `account` is credited and the `payee` debited. **It is an accounting entry only: no bank transfer, cheque or payment instruction is ever made.** **Create only**: it never changes, cancels or deletes a payment. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15; **installed service-account acceptance passed 2026-10-16** (COMP0002 / 2026, payments 216-223, overdrawn Cash and Bank included). **Through the cloud: not available** — the PC is relay-ready (same organization token, write rules, `details.paymentId`), but the AI Zeny cloud has no payment route.\n\n**How it works.**\n- **Numbers:** your `paymentReference` (1-60, first narration, unique among the company's payments of the year — the retry key) and the voucher number in a **manually numbered** payment series: `voucherNumber` (1-25), or by default your `paymentReference` when it fits 25 characters. Never an empty number; it must be new in the series (`409 PAYMENT_NUMBER_TAKEN`). An automatically numbered series is refused (`422 PAYMENT_SERIES_UNSUPPORTED`).\n- `allocations` (optional, 1-100, only for a payee kept bill by bill): `bill` (one the payee is still owed, at most its outstanding) or `newReference` (an advance, a number new to the payee; due on the payment date unless `dueDate`). **Amounts are positive**; AI Zeny records them as debits, as BUSY does. The rest stays on account (`unallocatedAmount`).\n- `instrumentNumber` and `shortNarration` go on the payee's line; an instrument type is not accepted.\n- **Never refused for an insufficient balance** (owner decision PY-10): a payment may leave Cash, Bank or Bank OD negative, as in BUSY. `data.accountBalanceAfter` = `{ asOfDate, balance, side }`: the paying account's balance at the **end of the payment date** (`asOfDate`) — its opening plus every non-cancelled, non-opening voucher dated on or before that day, this payment included; `balance` **positive = funds held (debit), negative = overdrawn (credit)**; `side` `debit` / `credit` / `nil`. Read from BUSY after the save.\n- AI Zeny compares BUSY's read-back, the saved rows (signs, `CashFlow`, bill rows) and each settled bill's outstanding before answering. Payments, receipts, sales returns, purchases and purchase returns share one lock on the PC.\n\n**Refused before BUSY:** an unknown master (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), a reference already held (`409 PAYMENT_REFERENCE_TAKEN`, `details.paymentId`), a held number (`409 PAYMENT_NUMBER_TAKEN`), a held new-reference name (`409 PAYMENT_NEW_REFERENCE_TAKEN`), a bill the payee is not owed (`422 PAYMENT_BILL_NOT_FOUND`), over-settlement (`422 PAYMENT_BILL_OVERSETTLED`), allocations for a payee not kept bill by bill (`422 PAYMENT_ALLOCATION_UNSUPPORTED`), a non-cash/bank account or a cash/bank payee (`422 PAYMENT_ACCOUNT_UNSUPPORTED`), an automatic series (`422`), 3 decimals or allocations above the amount (`400`).\n\n**Safe test guidance**\n- Select a development-test `companyCode` (`COMP0002` / FY 2026 in this environment; use `COMP0001` for Access tests). With `autoVoucherReferences=yes`, each Local Send generates and stores a fresh 25-character synthetic `paymentReference`. Set that switch to `no` to supply your own unique reference. The reference is also the default voucher number and advance number.\n- **Replace the example payee `AZPM-PAY PAYEE`** (it does not exist, so the example is refused with `422 MASTER_REFERENCE_NOT_FOUND` and nothing is written) with a **fresh dedicated test account** kept bill by bill. Do not use the PoC's or acceptance's records (`AZPOC-PAY …`, `AZSVC-PAY …`, accounts 1368-1373, payments 191-209 and 216-223) and do not settle their bills.\n- COMP0002's Cash and ICICI Bank are in credit (overdrawn) after the PoC and the acceptance: expect a negative `accountBalanceAfter`; the payment is still made.\n- Nothing is deleted automatically: a created test payment stays in BUSY.\n- **Never retry blindly.** Automatic references change on each Send, so another Send can create another voucher; reconcile an uncertain result first. Sending the same `paymentReference` again is refused (`409 PAYMENT_REFERENCE_TAKEN`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `paymentId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or a settled bill differ (`details.paymentId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC, up to 2 minutes: give the request a long timeout. Body up to 64 KiB.\n\n**Sets:** `paymentId` on success (usable as `voucherId` with `voucherType` `payment` in the Voucher PDF request). Public guide: `docs/public/api/payment-create.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PAYMENT_BILL_NOT_FOUND\",\n      \"message\": \"This number is not an outstanding bill of the payee in BUSY (a bill the payee is still owed). Check the bill's number, or send the amount as a new reference or leave it on account.\",\n      \"field\": \"allocations[0].bill.number\"\n    },\n    \"requestId\": \"rq_SYNTHETIC0000000000000003\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"e1d6fbc3-7c1e-47a5-9ef8-ac5bb7b8fea4","name":"504 — BUSY_WRITE_UNCERTAIN (reconciled: found; never resend; synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"payee\": { \"name\": \"AZPM-PAY PAYEE\" },\n  \"amount\": 10,\n  \"allocations\": [\n    { \"newReference\": { \"number\": \"{{paymentReference}}\" }, \"amount\": 10 }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/payment-create","description":"**Local** · `POST {{baseUrl}}/api/v1/payment-create` · Bearer `{{localApiToken}}` (collection auth) · **⚠ Writes to BUSY** (Development Local Send requires no separate confirmation)\n**Required:** `companyCode`, `financialYear`, `paymentReference`, `date`, `account`, `payee`, `amount` · **Optional:** `voucherNumber`, `voucherSeries`, `allocations`, `instrumentNumber`, `shortNarration`, `narration` · operation `busy.payments.create`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Access companies (2026-10-18):** runs on SQL Server companies with a SQL login **and** on BUSY companies kept in Access files (opened with BUSY's `OpenDBForYear` and the data folder; no SQL sign-in). Implemented 2026-10-18 (`5676376`); **installed service-account acceptance on Access passed 2026-10-19** (installed Host as `.\\AIZenySvc`, COMP0001 / FY 2026: every write row, the settings and numbering refusals on an isolated settings-off copy, independent Access ODBC and BUSY read-back agree; the SQL Server regression on COMP0002 passed too). The cloud relay on Access is not yet shown (`docs/LOCAL-API.md` 5aq).\n\n---\n\n**Mutating — writes to the BUSY books. Run manually, one at a time.** `busy.payments.create` (`POST /api/v1/payment-create`) records one BUSY **payment voucher** through BUSY's own COM component on this PC: the cash, bank or bank OD `account` is credited and the `payee` debited. **It is an accounting entry only: no bank transfer, cheque or payment instruction is ever made.** **Create only**: it never changes, cancels or deletes a payment. **SQL Server companies with a SQL login, or Access companies**. Never run from scripts. **Status:** implemented 2026-10-15; **installed service-account acceptance passed 2026-10-16** (COMP0002 / 2026, payments 216-223, overdrawn Cash and Bank included). **Through the cloud: not available** — the PC is relay-ready (same organization token, write rules, `details.paymentId`), but the AI Zeny cloud has no payment route.\n\n**How it works.**\n- **Numbers:** your `paymentReference` (1-60, first narration, unique among the company's payments of the year — the retry key) and the voucher number in a **manually numbered** payment series: `voucherNumber` (1-25), or by default your `paymentReference` when it fits 25 characters. Never an empty number; it must be new in the series (`409 PAYMENT_NUMBER_TAKEN`). An automatically numbered series is refused (`422 PAYMENT_SERIES_UNSUPPORTED`).\n- `allocations` (optional, 1-100, only for a payee kept bill by bill): `bill` (one the payee is still owed, at most its outstanding) or `newReference` (an advance, a number new to the payee; due on the payment date unless `dueDate`). **Amounts are positive**; AI Zeny records them as debits, as BUSY does. The rest stays on account (`unallocatedAmount`).\n- `instrumentNumber` and `shortNarration` go on the payee's line; an instrument type is not accepted.\n- **Never refused for an insufficient balance** (owner decision PY-10): a payment may leave Cash, Bank or Bank OD negative, as in BUSY. `data.accountBalanceAfter` = `{ asOfDate, balance, side }`: the paying account's balance at the **end of the payment date** (`asOfDate`) — its opening plus every non-cancelled, non-opening voucher dated on or before that day, this payment included; `balance` **positive = funds held (debit), negative = overdrawn (credit)**; `side` `debit` / `credit` / `nil`. Read from BUSY after the save.\n- AI Zeny compares BUSY's read-back, the saved rows (signs, `CashFlow`, bill rows) and each settled bill's outstanding before answering. Payments, receipts, sales returns, purchases and purchase returns share one lock on the PC.\n\n**Refused before BUSY:** an unknown master (`422 MASTER_REFERENCE_NOT_FOUND`; BUSY would create it), a reference already held (`409 PAYMENT_REFERENCE_TAKEN`, `details.paymentId`), a held number (`409 PAYMENT_NUMBER_TAKEN`), a held new-reference name (`409 PAYMENT_NEW_REFERENCE_TAKEN`), a bill the payee is not owed (`422 PAYMENT_BILL_NOT_FOUND`), over-settlement (`422 PAYMENT_BILL_OVERSETTLED`), allocations for a payee not kept bill by bill (`422 PAYMENT_ALLOCATION_UNSUPPORTED`), a non-cash/bank account or a cash/bank payee (`422 PAYMENT_ACCOUNT_UNSUPPORTED`), an automatic series (`422`), 3 decimals or allocations above the amount (`400`).\n\n**Safe test guidance**\n- Select a development-test `companyCode` (`COMP0002` / FY 2026 in this environment; use `COMP0001` for Access tests). With `autoVoucherReferences=yes`, each Local Send generates and stores a fresh 25-character synthetic `paymentReference`. Set that switch to `no` to supply your own unique reference. The reference is also the default voucher number and advance number.\n- **Replace the example payee `AZPM-PAY PAYEE`** (it does not exist, so the example is refused with `422 MASTER_REFERENCE_NOT_FOUND` and nothing is written) with a **fresh dedicated test account** kept bill by bill. Do not use the PoC's or acceptance's records (`AZPOC-PAY …`, `AZSVC-PAY …`, accounts 1368-1373, payments 191-209 and 216-223) and do not settle their bills.\n- COMP0002's Cash and ICICI Bank are in credit (overdrawn) after the PoC and the acceptance: expect a negative `accountBalanceAfter`; the payment is still made.\n- Nothing is deleted automatically: a created test payment stays in BUSY.\n- **Never retry blindly.** Automatic references change on each Send, so another Send can create another voucher; reconcile an uncertain result first. Sending the same `paymentReference` again is refused (`409 PAYMENT_REFERENCE_TAKEN`) if the first send saved. After `504 BUSY_WRITE_UNCERTAIN`, read `metadata.error.details.reconciliation` (`found` + `paymentId`, `notFound`, `notChecked`) and check BUSY first.\n- `502 BUSY_WRITE_UNVERIFIED` means BUSY **did** save but its read-back, saved rows or a settled bill differ (`details.paymentId`, `details.mismatchedFields`).\n- One BUSY job at a time on the PC, up to 2 minutes: give the request a long timeout. Body up to 64 KiB.\n\n**Sets:** `paymentId` on success (usable as `voucherId` with `voucherType` `payment` in the Voucher PDF request). Public guide: `docs/public/api/payment-create.md`.\n\n## Optional durable write queue (Windows Local API source)\n`queue` is an optional strict boolean at the voucher/master request root. Omit it or send `false` for the existing synchronous flow and its normal response. Add `\"queue\": true` to this same JSON body to durably accept a job with HTTP 202; business validation and BUSY insertion then run later. HTTP 202 is acceptance, not a saved master/voucher. Do not infer success from the acknowledgement; inspect the final result with `GET /api/v1/write-jobs/{id}` or BUSY Data → Write jobs. Existing plan, provider and operation validation still apply; a queued validation refusal is recorded in the job.\n\nOptional `X-Request-Id`: 1–128 ASCII letters/digits plus `. _ : -`. The safe default is to omit this header; for a deliberate retry after a lost acknowledgement, use the exact same body, company/FY, operation and request ID. A changed submission with an existing ID returns `409 WRITE_QUEUE_REQUEST_CONFLICT`. `503 WRITE_QUEUE_UNAVAILABLE` refuses queue acceptance without switching to a synchronous write. An uncertain or unverified final result must be reconciled, never blindly resent. No per-request callback URL is supported.\n\nPostman includes a disabled `X-Request-Id: {{writeRequestId}}` header on this request. Set `writeRequestId` to a fresh value and explicitly enable the header only when you intend to submit or reconcile that exact request ID. The development environment does not store an ID by default. For a new business write use a fresh ID or omit the header so the Host generates one. The 202 saved response is synthetic and shows the envelope; it does not prove installed-service acceptance.\n"},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"BUSY stopped while saving the payment; a payment with this paymentReference exists now (metadata.error.details.paymentId). Check it in BUSY; do not send it again.\",\n      \"details\": { \"paymentId\": 8931, \"reconciliation\": \"found\" }\n    },\n    \"requestId\": \"rq_SYNTHETIC0000000000000004\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"dbbc1f4c-3f81-b7a4-f3cf-597f5ed52a7b","name":"202 – durable job accepted (synthetic; BUSY result pending)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"account\": {\n    \"name\": \"Cash\"\n  },\n  \"payee\": {\n    \"name\": \"AZPM-PAY PAYEE\"\n  },\n  \"amount\": 10,\n  \"allocations\": [\n    {\n      \"newReference\": {\n        \"number\": \"{{paymentReference}}\"\n      },\n      \"amount\": 10\n    }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\",\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/payment-create"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"},{"value":"synthetic-queue-001","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.payments.create\",\n    \"requestId\": \"synthetic-queue-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"}],"_postman_id":"189dceb0-dad7-46b9-d68f-8c73d267f2e9"},{"name":"⚠ EXPECTED REFUSAL 400 – sales-order-create Manual amounts omitted (synthetic)","id":"69b8ca27-0208-b790-4aab-14593ff9f4b9","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 3,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Synthetic colour: blue\",\n        \"\",\n        \"Synthetic size: large\"\n      ]\n    },\n    {\n      \"item\": {\n        \"code\": 1348\n      },\n      \"quantity\": 1,\n      \"rate\": 200\n    }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-order-create","description":"<p>Expected refusal only, Windows Local. This complete synthetic request intentionally sets Manual but omits every line's <code>amounts</code> and voucher <code>totals</code>, so validation must return exactly <code>400 INVALID_PARAMETER</code> before a BUSY save. It is not a success or provider-capability test. The extra <code>confirmExpectedRefusal=yes</code> one-send guard stays unset by default; the ordinary Local mutation confirmations and target check also apply. Never run this while merely reviewing examples. Cloud Relay capability is not implied.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","sales-order-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"69b8ca27-0208-b790-4aab-14593ff9f4b9"},{"name":"⚠ EXPECTED REFUSAL 400 – sales-invoice-create Manual amounts omitted (synthetic)","id":"86b0cca2-4778-3efc-1d5e-2c488c44987a","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-14\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 2,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Postman test line\"\n      ]\n    },\n    {\n      \"item\": {\n        \"name\": \"Parle G\"\n      },\n      \"quantity\": 2.5,\n      \"rate\": 20.1\n    }\n  ],\n  \"narration\": \"Postman test invoice\",\n  \"transport\": \"Synthetic Transport Co\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-invoice-create","description":"<p>Expected refusal only, Windows Local. This complete synthetic request intentionally sets Manual but omits every line's <code>amounts</code> and voucher <code>totals</code>, so validation must return exactly <code>400 INVALID_PARAMETER</code> before a BUSY save. It is not a success or provider-capability test. The extra <code>confirmExpectedRefusal=yes</code> one-send guard stays unset by default; the ordinary Local mutation confirmations and target check also apply. Never run this while merely reviewing examples. Cloud Relay capability is not implied.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","sales-invoice-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"86b0cca2-4778-3efc-1d5e-2c488c44987a"},{"name":"⚠ EXPECTED REFUSAL 400 – sales-return-create Manual amounts omitted (synthetic)","id":"bed512e2-59be-e860-2f42-a5d1407c1b08","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 150,\n      \"description\": [\n        \"Postman test return\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test sales return (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/sales-return-create","description":"<p>Expected refusal only, Windows Local. This complete synthetic request intentionally sets Manual but omits every line's <code>amounts</code> and voucher <code>totals</code>, so validation must return exactly <code>400 INVALID_PARAMETER</code> before a BUSY save. It is not a success or provider-capability test. The extra <code>confirmExpectedRefusal=yes</code> one-send guard stays unset by default; the ordinary Local mutation confirmations and target check also apply. Never run this while merely reviewing examples. Cloud Relay capability is not implied.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","sales-return-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"bed512e2-59be-e860-2f42-a5d1407c1b08"},{"name":"⚠ EXPECTED REFUSAL 400 – purchase-create Manual amounts omitted (synthetic)","id":"3a05bbd5-4d43-8a53-09ed-87f9951be5bf","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": {\n    \"number\": \"{{purchaseReference}}\",\n    \"date\": \"2026-10-15\"\n  },\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100,\n      \"description\": [\n        \"Postman test purchase\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-create","description":"<p>Expected refusal only, Windows Local. This complete synthetic request intentionally sets Manual but omits every line's <code>amounts</code> and voucher <code>totals</code>, so validation must return exactly <code>400 INVALID_PARAMETER</code> before a BUSY save. It is not a success or provider-capability test. The extra <code>confirmExpectedRefusal=yes</code> one-send guard stays unset by default; the ordinary Local mutation confirmations and target check also apply. Never run this while merely reviewing examples. Cloud Relay capability is not implied.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","purchase-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"3a05bbd5-4d43-8a53-09ed-87f9951be5bf"},{"name":"⚠ EXPECTED REFUSAL 400 – purchase-return-create Manual amounts omitted (synthetic)","id":"e5bb95ac-810e-8954-3c24-3f0d341f8a21","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": {\n    \"name\": \"Main\"\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PRT SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100\n    }\n  ],\n  \"adjustment\": {\n    \"newReference\": {\n      \"number\": \"{{purchaseReturnReference}}\"\n    }\n  },\n  \"narration\": \"Postman test purchase return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-return-create","description":"<p>Expected refusal only, Windows Local. This complete synthetic request intentionally sets Manual but omits every line's <code>amounts</code> and voucher <code>totals</code>, so validation must return exactly <code>400 INVALID_PARAMETER</code> before a BUSY save. It is not a success or provider-capability test. The extra <code>confirmExpectedRefusal=yes</code> one-send guard stays unset by default; the ordinary Local mutation confirmations and target check also apply. Never run this while merely reviewing examples. Cloud Relay capability is not implied.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","purchase-return-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"e5bb95ac-810e-8954-3c24-3f0d341f8a21"},{"name":"⚠ BUSY stock transfer – create (writes to BUSY)","id":"cc297f3b-39b0-9a36-33dc-b68151404320","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"transferReference\": \"{{stockTransferReference}}\",\n  \"date\": \"{{financialYear}}-10-21\",\n  \"sourceMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_SOURCE_CENTRE\"\n  },\n  \"destinationMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_DESTINATION_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/stock-transfer-create","description":"<p><strong>Local source contract only:</strong> POST {{baseUrl}}/api/v1/stock-transfer-create; operation <code>busy.stock-transfers.create</code>. This request was added after source merge <code>c13aca1</code>. Installed service-account acceptance and public release are pending; the installed 0.0.16 Host is not claimed to support it. Cloud support is separate.</p>\n<p><strong>Before a Send:</strong> use only the approved development PC/test company and fresh synthetic data; replace the three REPLACE_WITH_ master placeholders with real, existing, untracked synthetic fixture names. Source/destination centres must differ. The voucher series must be automatic type 5; omit voucherSeries only if exactly one qualifies, otherwise add {code} or {name}. Close BUSY and take a verified backup before any live synthetic write. The request skips on placeholders, missing scope/reference, a nonlocal URL, an unresolved prior Stock Transfer or missing one-send confirmation. The collection's existing autoConfirmLocal=yes convention arms confirmMutating on the loopback development URL. The pre-request script generates a fresh 25-character stockTransferReference when autoVoucherReferences=yes and saves it for reconciliation; otherwise set a fresh stockTransferReference yourself. A second Send generates another reference: <strong>never retry an uncertain or unverified result</strong>. This request does not install the source code.</p>\n<p><strong>Body:</strong> companyCode, financialYear, unique transferReference (trimmed 1–60), date (YYYY-MM-DD in FY), two existing material-centre refs and 1–100 common lines. Each line has existing untracked item {code} or {name}, positive main-unit quantity (at most 3 decimals and company precision), nonnegative base-currency rate (at most 2 decimals); optional listPrice and 1–4 positional description strings. Optional voucherSeries, documentNumber/documentDate, narration and strict boolean queue (default false). Unknown fields, independent source lines, GST/stock-tracking/costing overrides and per-request webhook URL are refused. A company webhook is configured separately. See docs/public/api/stock-transfer-create.md.</p>\n<p><strong>Outcomes:</strong> sync 200 proves native read-back plus independent saved rows; queue:true 202 is only encrypted job acceptance with data:null, so inspect writeJobId/Write jobs. The X-Request-Id header is disabled by default; enable it only with an explicitly chosen fixed writeRequestId for a deliberate idempotent submission, and do not mint another ID after uncertainty. An explicitly chosen stockTransferExpectedRefusal value <code>STATUS ERROR_CODE</code> makes the test require that exact status and error code. Synthetic 400/409/502/504 examples illustrate contracts, not live evidence. The pre-send guard sets stockTransferPendingReview=yes before sending; only an exact validated 200 or deliberately selected exact refusal clears it. A 202 job, missing response, failed assertion, 502 BUSY_WRITE_UNVERIFIED or 504 BUSY_WRITE_UNCERTAIN keeps the review flag. Inspect BUSY and any prior job before manually clearing it. No blind retry or delete. Trial/Pro/Max write capability and normal company/year/provider gates apply.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Installed public v0.0.30 predates this merged source; these are documentation examples only. Do not Send until a newer candidate with this source is installed and the target BUSY series is verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"transferReference\": \"{{stockTransferReference}}\",\n  \"date\": \"{{financialYear}}-10-21\",\n  \"sourceMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_SOURCE_CENTRE\"\n  },\n  \"destinationMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_DESTINATION_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false,\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\",\n  \"voucherSeries\": {\n    \"code\": 101\n  }\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"transferReference\": \"{{stockTransferReference}}\",\n  \"date\": \"{{financialYear}}-10-21\",\n  \"sourceMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_SOURCE_CENTRE\"\n  },\n  \"destinationMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_DESTINATION_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false,\n  \"numberingMode\": \"auto\",\n  \"voucherSeries\": {\n    \"code\": 102\n  }\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","stock-transfer-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"b7b0c1bf-cc4f-c4fa-fe45-c245ad214dcf","name":"SYNTHETIC — 200 created; native + stored-row proof","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"transferReference\": \"{{stockTransferReference}}\",\n  \"date\": \"{{financialYear}}-10-21\",\n  \"sourceMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_SOURCE_CENTRE\"\n  },\n  \"destinationMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_DESTINATION_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/stock-transfer-create","description":"**Local source contract only:** POST {{baseUrl}}/api/v1/stock-transfer-create; operation `busy.stock-transfers.create`. This request was added after source merge `c13aca1`. Installed service-account acceptance and public release are pending; the installed 0.0.16 Host is not claimed to support it. Cloud support is separate.\n\n**Before a Send:** use only the approved development PC/test company and fresh synthetic data; replace the three REPLACE_WITH_ master placeholders with real, existing, untracked synthetic fixture names. Source/destination centres must differ. The voucher series must be automatic type 5; omit voucherSeries only if exactly one qualifies, otherwise add {code} or {name}. Close BUSY and take a verified backup before any live synthetic write. The request skips on placeholders, missing scope/reference, a nonlocal URL, an unresolved prior Stock Transfer or missing one-send confirmation. The collection's existing autoConfirmLocal=yes convention arms confirmMutating on the loopback development URL. The pre-request script generates a fresh 25-character stockTransferReference when autoVoucherReferences=yes and saves it for reconciliation; otherwise set a fresh stockTransferReference yourself. A second Send generates another reference: **never retry an uncertain or unverified result**. This request does not install the source code.\n\n**Body:** companyCode, financialYear, unique transferReference (trimmed 1–60), date (YYYY-MM-DD in FY), two existing material-centre refs and 1–100 common lines. Each line has existing untracked item {code} or {name}, positive main-unit quantity (at most 3 decimals and company precision), nonnegative base-currency rate (at most 2 decimals); optional listPrice and 1–4 positional description strings. Optional voucherSeries, documentNumber/documentDate, narration and strict boolean queue (default false). Unknown fields, independent source lines, GST/stock-tracking/costing overrides and per-request webhook URL are refused. A company webhook is configured separately. See docs/public/api/stock-transfer-create.md.\n\n**Outcomes:** sync 200 proves native read-back plus independent saved rows; queue:true 202 is only encrypted job acceptance with data:null, so inspect writeJobId/Write jobs. The X-Request-Id header is disabled by default; enable it only with an explicitly chosen fixed writeRequestId for a deliberate idempotent submission, and do not mint another ID after uncertainty. An explicitly chosen stockTransferExpectedRefusal value `STATUS ERROR_CODE` makes the test require that exact status and error code. Synthetic 400/409/502/504 examples illustrate contracts, not live evidence. The pre-send guard sets stockTransferPendingReview=yes before sending; only an exact validated 200 or deliberately selected exact refusal clears it. A 202 job, missing response, failed assertion, 502 BUSY_WRITE_UNVERIFIED or 504 BUSY_WRITE_UNCERTAIN keeps the review flag. Inspect BUSY and any prior job before manually clearing it. No blind retry or delete. Trial/Pro/Max write capability and normal company/year/provider gates apply."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"transferId\": 9001,\n    \"transferNumber\": \"1/2026-27\",\n    \"transferReference\": \"AZSYNTHETIC001\",\n    \"date\": \"2026-10-21\",\n    \"voucherSeries\": {\n      \"code\": 7100,\n      \"name\": \"Synthetic Auto Series\"\n    },\n    \"sourceMaterialCenter\": {\n      \"code\": 7200,\n      \"name\": \"Synthetic Source\"\n    },\n    \"destinationMaterialCenter\": {\n      \"code\": 7201,\n      \"name\": \"Synthetic Destination\"\n    },\n    \"lines\": [\n      {\n        \"lineNumber\": 1,\n        \"item\": {\n          \"code\": 7300,\n          \"name\": \"Synthetic Item\"\n        },\n        \"unit\": {\n          \"code\": 7400,\n          \"name\": \"PCS\"\n        },\n        \"alternateUnit\": {\n          \"code\": 7400,\n          \"name\": \"PCS\"\n        },\n        \"conversionFactor\": 1,\n        \"quantity\": 2,\n        \"alternateQuantity\": 2,\n        \"rate\": 10,\n        \"alternateRate\": 10,\n        \"listPrice\": 10,\n        \"amount\": 20,\n        \"description\": []\n      }\n    ],\n    \"totalTransferValue\": 20,\n    \"documentNumber\": null,\n    \"documentDate\": null,\n    \"narration\": null\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.stock-transfers.create\",\n    \"requestId\": \"synthetic-stock-001\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 1,\n    \"verification\": [\n      \"busyReadBack\",\n      \"savedRows\"\n    ],\n    \"elapsedMs\": 80,\n    \"executedAt\": \"2026-10-21T10:00:00+00:00\"\n  }\n}"},{"id":"c625bd9c-3b67-96d0-8fff-66a51c577329","name":"SYNTHETIC — 202 queued; BUSY result pending","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"transferReference\": \"{{stockTransferReference}}\",\n  \"date\": \"{{financialYear}}-10-21\",\n  \"sourceMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_SOURCE_CENTRE\"\n  },\n  \"destinationMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_DESTINATION_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/stock-transfer-create","description":"**Local source contract only:** POST {{baseUrl}}/api/v1/stock-transfer-create; operation `busy.stock-transfers.create`. This request was added after source merge `c13aca1`. Installed service-account acceptance and public release are pending; the installed 0.0.16 Host is not claimed to support it. Cloud support is separate.\n\n**Before a Send:** use only the approved development PC/test company and fresh synthetic data; replace the three REPLACE_WITH_ master placeholders with real, existing, untracked synthetic fixture names. Source/destination centres must differ. The voucher series must be automatic type 5; omit voucherSeries only if exactly one qualifies, otherwise add {code} or {name}. Close BUSY and take a verified backup before any live synthetic write. The request skips on placeholders, missing scope/reference, a nonlocal URL, an unresolved prior Stock Transfer or missing one-send confirmation. The collection's existing autoConfirmLocal=yes convention arms confirmMutating on the loopback development URL. The pre-request script generates a fresh 25-character stockTransferReference when autoVoucherReferences=yes and saves it for reconciliation; otherwise set a fresh stockTransferReference yourself. A second Send generates another reference: **never retry an uncertain or unverified result**. This request does not install the source code.\n\n**Body:** companyCode, financialYear, unique transferReference (trimmed 1–60), date (YYYY-MM-DD in FY), two existing material-centre refs and 1–100 common lines. Each line has existing untracked item {code} or {name}, positive main-unit quantity (at most 3 decimals and company precision), nonnegative base-currency rate (at most 2 decimals); optional listPrice and 1–4 positional description strings. Optional voucherSeries, documentNumber/documentDate, narration and strict boolean queue (default false). Unknown fields, independent source lines, GST/stock-tracking/costing overrides and per-request webhook URL are refused. A company webhook is configured separately. See docs/public/api/stock-transfer-create.md.\n\n**Outcomes:** sync 200 proves native read-back plus independent saved rows; queue:true 202 is only encrypted job acceptance with data:null, so inspect writeJobId/Write jobs. The X-Request-Id header is disabled by default; enable it only with an explicitly chosen fixed writeRequestId for a deliberate idempotent submission, and do not mint another ID after uncertainty. An explicitly chosen stockTransferExpectedRefusal value `STATUS ERROR_CODE` makes the test require that exact status and error code. Synthetic 400/409/502/504 examples illustrate contracts, not live evidence. The pre-send guard sets stockTransferPendingReview=yes before sending; only an exact validated 200 or deliberately selected exact refusal clears it. A 202 job, missing response, failed assertion, 502 BUSY_WRITE_UNVERIFIED or 504 BUSY_WRITE_UNCERTAIN keeps the review flag. Inspect BUSY and any prior job before manually clearing it. No blind retry or delete. Trial/Pro/Max write capability and normal company/year/provider gates apply."},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.stock-transfers.create\",\n    \"requestId\": \"synthetic-stock-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"},{"id":"1ff40b04-7f2e-882f-b1fd-b6bb90e9de7a","name":"SYNTHETIC — 400 INVALID_PARAMETER; bad quantity","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"transferReference\": \"{{stockTransferReference}}\",\n  \"date\": \"{{financialYear}}-10-21\",\n  \"sourceMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_SOURCE_CENTRE\"\n  },\n  \"destinationMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_DESTINATION_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/stock-transfer-create","description":"**Local source contract only:** POST {{baseUrl}}/api/v1/stock-transfer-create; operation `busy.stock-transfers.create`. This request was added after source merge `c13aca1`. Installed service-account acceptance and public release are pending; the installed 0.0.16 Host is not claimed to support it. Cloud support is separate.\n\n**Before a Send:** use only the approved development PC/test company and fresh synthetic data; replace the three REPLACE_WITH_ master placeholders with real, existing, untracked synthetic fixture names. Source/destination centres must differ. The voucher series must be automatic type 5; omit voucherSeries only if exactly one qualifies, otherwise add {code} or {name}. Close BUSY and take a verified backup before any live synthetic write. The request skips on placeholders, missing scope/reference, a nonlocal URL, an unresolved prior Stock Transfer or missing one-send confirmation. The collection's existing autoConfirmLocal=yes convention arms confirmMutating on the loopback development URL. The pre-request script generates a fresh 25-character stockTransferReference when autoVoucherReferences=yes and saves it for reconciliation; otherwise set a fresh stockTransferReference yourself. A second Send generates another reference: **never retry an uncertain or unverified result**. This request does not install the source code.\n\n**Body:** companyCode, financialYear, unique transferReference (trimmed 1–60), date (YYYY-MM-DD in FY), two existing material-centre refs and 1–100 common lines. Each line has existing untracked item {code} or {name}, positive main-unit quantity (at most 3 decimals and company precision), nonnegative base-currency rate (at most 2 decimals); optional listPrice and 1–4 positional description strings. Optional voucherSeries, documentNumber/documentDate, narration and strict boolean queue (default false). Unknown fields, independent source lines, GST/stock-tracking/costing overrides and per-request webhook URL are refused. A company webhook is configured separately. See docs/public/api/stock-transfer-create.md.\n\n**Outcomes:** sync 200 proves native read-back plus independent saved rows; queue:true 202 is only encrypted job acceptance with data:null, so inspect writeJobId/Write jobs. The X-Request-Id header is disabled by default; enable it only with an explicitly chosen fixed writeRequestId for a deliberate idempotent submission, and do not mint another ID after uncertainty. An explicitly chosen stockTransferExpectedRefusal value `STATUS ERROR_CODE` makes the test require that exact status and error code. Synthetic 400/409/502/504 examples illustrate contracts, not live evidence. The pre-send guard sets stockTransferPendingReview=yes before sending; only an exact validated 200 or deliberately selected exact refusal clears it. A 202 job, missing response, failed assertion, 502 BUSY_WRITE_UNVERIFIED or 504 BUSY_WRITE_UNCERTAIN keeps the review flag. Inspect BUSY and any prior job before manually clearing it. No blind retry or delete. Trial/Pro/Max write capability and normal company/year/provider gates apply."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"quantity must be positive, at most 99999999.999, with at most 3 decimals, in main units.\",\n      \"field\": \"lines[0].quantity\"\n    },\n    \"requestId\": \"synthetic-stock-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"6f64f116-3d74-f418-d5a6-13792fc1ca90","name":"SYNTHETIC — 409 STOCK_TRANSFER_REFERENCE_TAKEN","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"transferReference\": \"{{stockTransferReference}}\",\n  \"date\": \"{{financialYear}}-10-21\",\n  \"sourceMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_SOURCE_CENTRE\"\n  },\n  \"destinationMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_DESTINATION_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/stock-transfer-create","description":"**Local source contract only:** POST {{baseUrl}}/api/v1/stock-transfer-create; operation `busy.stock-transfers.create`. This request was added after source merge `c13aca1`. Installed service-account acceptance and public release are pending; the installed 0.0.16 Host is not claimed to support it. Cloud support is separate.\n\n**Before a Send:** use only the approved development PC/test company and fresh synthetic data; replace the three REPLACE_WITH_ master placeholders with real, existing, untracked synthetic fixture names. Source/destination centres must differ. The voucher series must be automatic type 5; omit voucherSeries only if exactly one qualifies, otherwise add {code} or {name}. Close BUSY and take a verified backup before any live synthetic write. The request skips on placeholders, missing scope/reference, a nonlocal URL, an unresolved prior Stock Transfer or missing one-send confirmation. The collection's existing autoConfirmLocal=yes convention arms confirmMutating on the loopback development URL. The pre-request script generates a fresh 25-character stockTransferReference when autoVoucherReferences=yes and saves it for reconciliation; otherwise set a fresh stockTransferReference yourself. A second Send generates another reference: **never retry an uncertain or unverified result**. This request does not install the source code.\n\n**Body:** companyCode, financialYear, unique transferReference (trimmed 1–60), date (YYYY-MM-DD in FY), two existing material-centre refs and 1–100 common lines. Each line has existing untracked item {code} or {name}, positive main-unit quantity (at most 3 decimals and company precision), nonnegative base-currency rate (at most 2 decimals); optional listPrice and 1–4 positional description strings. Optional voucherSeries, documentNumber/documentDate, narration and strict boolean queue (default false). Unknown fields, independent source lines, GST/stock-tracking/costing overrides and per-request webhook URL are refused. A company webhook is configured separately. See docs/public/api/stock-transfer-create.md.\n\n**Outcomes:** sync 200 proves native read-back plus independent saved rows; queue:true 202 is only encrypted job acceptance with data:null, so inspect writeJobId/Write jobs. The X-Request-Id header is disabled by default; enable it only with an explicitly chosen fixed writeRequestId for a deliberate idempotent submission, and do not mint another ID after uncertainty. An explicitly chosen stockTransferExpectedRefusal value `STATUS ERROR_CODE` makes the test require that exact status and error code. Synthetic 400/409/502/504 examples illustrate contracts, not live evidence. The pre-send guard sets stockTransferPendingReview=yes before sending; only an exact validated 200 or deliberately selected exact refusal clears it. A 202 job, missing response, failed assertion, 502 BUSY_WRITE_UNVERIFIED or 504 BUSY_WRITE_UNCERTAIN keeps the review flag. Inspect BUSY and any prior job before manually clearing it. No blind retry or delete. Trial/Pro/Max write capability and normal company/year/provider gates apply."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"STOCK_TRANSFER_REFERENCE_TAKEN\",\n      \"message\": \"A stock transfer already holds this transferReference.\",\n      \"details\": {\n        \"transferId\": 9002\n      }\n    },\n    \"requestId\": \"synthetic-stock-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"05a3e038-9a3d-781d-fce2-2415bfc0cc1c","name":"SYNTHETIC — 409 STOCK_TRANSFER_CONFIGURATION_CHANGED","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"transferReference\": \"{{stockTransferReference}}\",\n  \"date\": \"{{financialYear}}-10-21\",\n  \"sourceMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_SOURCE_CENTRE\"\n  },\n  \"destinationMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_DESTINATION_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/stock-transfer-create","description":"**Local source contract only:** POST {{baseUrl}}/api/v1/stock-transfer-create; operation `busy.stock-transfers.create`. This request was added after source merge `c13aca1`. Installed service-account acceptance and public release are pending; the installed 0.0.16 Host is not claimed to support it. Cloud support is separate.\n\n**Before a Send:** use only the approved development PC/test company and fresh synthetic data; replace the three REPLACE_WITH_ master placeholders with real, existing, untracked synthetic fixture names. Source/destination centres must differ. The voucher series must be automatic type 5; omit voucherSeries only if exactly one qualifies, otherwise add {code} or {name}. Close BUSY and take a verified backup before any live synthetic write. The request skips on placeholders, missing scope/reference, a nonlocal URL, an unresolved prior Stock Transfer or missing one-send confirmation. The collection's existing autoConfirmLocal=yes convention arms confirmMutating on the loopback development URL. The pre-request script generates a fresh 25-character stockTransferReference when autoVoucherReferences=yes and saves it for reconciliation; otherwise set a fresh stockTransferReference yourself. A second Send generates another reference: **never retry an uncertain or unverified result**. This request does not install the source code.\n\n**Body:** companyCode, financialYear, unique transferReference (trimmed 1–60), date (YYYY-MM-DD in FY), two existing material-centre refs and 1–100 common lines. Each line has existing untracked item {code} or {name}, positive main-unit quantity (at most 3 decimals and company precision), nonnegative base-currency rate (at most 2 decimals); optional listPrice and 1–4 positional description strings. Optional voucherSeries, documentNumber/documentDate, narration and strict boolean queue (default false). Unknown fields, independent source lines, GST/stock-tracking/costing overrides and per-request webhook URL are refused. A company webhook is configured separately. See docs/public/api/stock-transfer-create.md.\n\n**Outcomes:** sync 200 proves native read-back plus independent saved rows; queue:true 202 is only encrypted job acceptance with data:null, so inspect writeJobId/Write jobs. The X-Request-Id header is disabled by default; enable it only with an explicitly chosen fixed writeRequestId for a deliberate idempotent submission, and do not mint another ID after uncertainty. An explicitly chosen stockTransferExpectedRefusal value `STATUS ERROR_CODE` makes the test require that exact status and error code. Synthetic 400/409/502/504 examples illustrate contracts, not live evidence. The pre-send guard sets stockTransferPendingReview=yes before sending; only an exact validated 200 or deliberately selected exact refusal clears it. A 202 job, missing response, failed assertion, 502 BUSY_WRITE_UNVERIFIED or 504 BUSY_WRITE_UNCERTAIN keeps the review flag. Inspect BUSY and any prior job before manually clearing it. No blind retry or delete. Trial/Pro/Max write capability and normal company/year/provider gates apply."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"STOCK_TRANSFER_CONFIGURATION_CHANGED\",\n      \"message\": \"BUSY masters or settings changed during preflight. Review the configuration before a new attempt.\"\n    },\n    \"requestId\": \"synthetic-stock-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"92c946ad-aece-e487-5dcf-1664c7481bb0","name":"SYNTHETIC — 502 BUSY_WRITE_UNVERIFIED; saved, reconcile","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"transferReference\": \"{{stockTransferReference}}\",\n  \"date\": \"{{financialYear}}-10-21\",\n  \"sourceMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_SOURCE_CENTRE\"\n  },\n  \"destinationMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_DESTINATION_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/stock-transfer-create","description":"**Local source contract only:** POST {{baseUrl}}/api/v1/stock-transfer-create; operation `busy.stock-transfers.create`. This request was added after source merge `c13aca1`. Installed service-account acceptance and public release are pending; the installed 0.0.16 Host is not claimed to support it. Cloud support is separate.\n\n**Before a Send:** use only the approved development PC/test company and fresh synthetic data; replace the three REPLACE_WITH_ master placeholders with real, existing, untracked synthetic fixture names. Source/destination centres must differ. The voucher series must be automatic type 5; omit voucherSeries only if exactly one qualifies, otherwise add {code} or {name}. Close BUSY and take a verified backup before any live synthetic write. The request skips on placeholders, missing scope/reference, a nonlocal URL, an unresolved prior Stock Transfer or missing one-send confirmation. The collection's existing autoConfirmLocal=yes convention arms confirmMutating on the loopback development URL. The pre-request script generates a fresh 25-character stockTransferReference when autoVoucherReferences=yes and saves it for reconciliation; otherwise set a fresh stockTransferReference yourself. A second Send generates another reference: **never retry an uncertain or unverified result**. This request does not install the source code.\n\n**Body:** companyCode, financialYear, unique transferReference (trimmed 1–60), date (YYYY-MM-DD in FY), two existing material-centre refs and 1–100 common lines. Each line has existing untracked item {code} or {name}, positive main-unit quantity (at most 3 decimals and company precision), nonnegative base-currency rate (at most 2 decimals); optional listPrice and 1–4 positional description strings. Optional voucherSeries, documentNumber/documentDate, narration and strict boolean queue (default false). Unknown fields, independent source lines, GST/stock-tracking/costing overrides and per-request webhook URL are refused. A company webhook is configured separately. See docs/public/api/stock-transfer-create.md.\n\n**Outcomes:** sync 200 proves native read-back plus independent saved rows; queue:true 202 is only encrypted job acceptance with data:null, so inspect writeJobId/Write jobs. The X-Request-Id header is disabled by default; enable it only with an explicitly chosen fixed writeRequestId for a deliberate idempotent submission, and do not mint another ID after uncertainty. An explicitly chosen stockTransferExpectedRefusal value `STATUS ERROR_CODE` makes the test require that exact status and error code. Synthetic 400/409/502/504 examples illustrate contracts, not live evidence. The pre-send guard sets stockTransferPendingReview=yes before sending; only an exact validated 200 or deliberately selected exact refusal clears it. A 202 job, missing response, failed assertion, 502 BUSY_WRITE_UNVERIFIED or 504 BUSY_WRITE_UNCERTAIN keeps the review flag. Inspect BUSY and any prior job before manually clearing it. No blind retry or delete. Trial/Pro/Max write capability and normal company/year/provider gates apply."},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNVERIFIED\",\n      \"message\": \"BUSY saved the stock transfer but read-back differs; inspect the saved reference.\",\n      \"details\": {\n        \"transferId\": 9003,\n        \"mismatchedFields\": [\n          \"lines[0].amount\"\n        ]\n      }\n    },\n    \"requestId\": \"synthetic-stock-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"527f62ec-4ef0-5ced-c1ba-f35341ef4666","name":"SYNTHETIC — 504 BUSY_WRITE_UNCERTAIN; do not resend","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{writeRequestId}}","key":"X-Request-Id","disabled":true}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"transferReference\": \"{{stockTransferReference}}\",\n  \"date\": \"{{financialYear}}-10-21\",\n  \"sourceMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_SOURCE_CENTRE\"\n  },\n  \"destinationMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_DESTINATION_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/stock-transfer-create","description":"**Local source contract only:** POST {{baseUrl}}/api/v1/stock-transfer-create; operation `busy.stock-transfers.create`. This request was added after source merge `c13aca1`. Installed service-account acceptance and public release are pending; the installed 0.0.16 Host is not claimed to support it. Cloud support is separate.\n\n**Before a Send:** use only the approved development PC/test company and fresh synthetic data; replace the three REPLACE_WITH_ master placeholders with real, existing, untracked synthetic fixture names. Source/destination centres must differ. The voucher series must be automatic type 5; omit voucherSeries only if exactly one qualifies, otherwise add {code} or {name}. Close BUSY and take a verified backup before any live synthetic write. The request skips on placeholders, missing scope/reference, a nonlocal URL, an unresolved prior Stock Transfer or missing one-send confirmation. The collection's existing autoConfirmLocal=yes convention arms confirmMutating on the loopback development URL. The pre-request script generates a fresh 25-character stockTransferReference when autoVoucherReferences=yes and saves it for reconciliation; otherwise set a fresh stockTransferReference yourself. A second Send generates another reference: **never retry an uncertain or unverified result**. This request does not install the source code.\n\n**Body:** companyCode, financialYear, unique transferReference (trimmed 1–60), date (YYYY-MM-DD in FY), two existing material-centre refs and 1–100 common lines. Each line has existing untracked item {code} or {name}, positive main-unit quantity (at most 3 decimals and company precision), nonnegative base-currency rate (at most 2 decimals); optional listPrice and 1–4 positional description strings. Optional voucherSeries, documentNumber/documentDate, narration and strict boolean queue (default false). Unknown fields, independent source lines, GST/stock-tracking/costing overrides and per-request webhook URL are refused. A company webhook is configured separately. See docs/public/api/stock-transfer-create.md.\n\n**Outcomes:** sync 200 proves native read-back plus independent saved rows; queue:true 202 is only encrypted job acceptance with data:null, so inspect writeJobId/Write jobs. The X-Request-Id header is disabled by default; enable it only with an explicitly chosen fixed writeRequestId for a deliberate idempotent submission, and do not mint another ID after uncertainty. An explicitly chosen stockTransferExpectedRefusal value `STATUS ERROR_CODE` makes the test require that exact status and error code. Synthetic 400/409/502/504 examples illustrate contracts, not live evidence. The pre-send guard sets stockTransferPendingReview=yes before sending; only an exact validated 200 or deliberately selected exact refusal clears it. A 202 job, missing response, failed assertion, 502 BUSY_WRITE_UNVERIFIED or 504 BUSY_WRITE_UNCERTAIN keeps the review flag. Inspect BUSY and any prior job before manually clearing it. No blind retry or delete. Trial/Pro/Max write capability and normal company/year/provider gates apply."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"The stock transfer outcome is uncertain; reconcile before a new attempt.\",\n      \"details\": {\n        \"reconciliation\": \"notChecked\"\n      }\n    },\n    \"requestId\": \"synthetic-stock-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"cc297f3b-39b0-9a36-33dc-b68151404320"},{"name":"⚠ BUSY purchase order – create (writes to BUSY)","id":"d81a29c3-761e-4c83-a12e-2251ed35b2b0","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{purchaseOrderReference}}\",\n  \"date\": \"2026-10-21\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_PO_SERIES\"\n  },\n  \"supplier\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_SUPPLIER\"\n  },\n  \"purchaseType\": {\n    \"name\": \"REPLACE_WITH_SUPPORTED_GST_PURCHASE_TYPE\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100\n    }\n  ],\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/purchase-order-create","description":"<p><strong>Local source contract only:</strong> POST {{baseUrl}}/api/v1/purchase-order-create; operation <code>busy.purchase-orders.create</code>. Source <code>87ee29a</code> is merged. This request is guarded for development; installed service-account acceptance and public release must be recorded separately. No deployed Cloud Purchase Order route is claimed.</p>\n<p>Before a Send, use only COMP0001/COMP0002 FY2026 on this development PC after a verified backup and with BUSY closed. Replace every REPLACE_WITH_ value with an existing synthetic fixture. The Purchase Order series must be automatic type 13; choose a supported local/central purchase type whose inclusive setting matches pricingMode. Set a fresh orderReference (1–60 characters), or keep autoVoucherReferences=yes to generate one. <code>purchaseOrderPendingReview=yes</code> is set before Send and blocks another attempt until a verified saved result or a deliberately selected exact pre-save refusal. A missing response, 202 job, 502 or 504 keeps it set. Never blindly resend; inspect BUSY and the job. One-send <code>confirmMutating=yes</code> and loopback guard apply.</p>\n<p>Body: required companyCode, financialYear, orderReference, date, supplier, purchaseType, materialCenter and 1–100 lines with existing untracked same-unit item, positive quantity and rate. voucherSeries is optional only when exactly one automatic series qualifies. <code>taxCalculation</code> defaults to auto; <code>pricingMode</code> defaults to gstExclusive. Manual requires every line.amounts and voucher totals (taxableAmount, cgst, sgst, igst, amount); Auto forbids both. Optional line discountPercent/mrp/description/dueDate and header dueDate/documentNumber/documentDate/narration/billSundries follow docs/public/api/purchase-order-create.md. <code>queue:false</code> sync success requires exact 200, native read-back and saved rows. <code>queue:true</code> returns 202 job receipt, not a saved order. An optional X-Request-Id may be deliberately supplied for queue deduplication; it is not the orderReference. <code>purchaseOrderExpectedRefusal</code> uses exact <code>STATUS ERROR_CODE</code> for a deliberate pre-save refusal and must never select 502/504. Synthetic examples are illustrative, not live evidence. Trial/Pro/Max and normal company/year/provider gates apply. No stock, ledger or payable posting is expected.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Installed public v0.0.30 predates this merged source; these are documentation examples only. Do not Send until a newer candidate with this source is installed and the target BUSY series is verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{purchaseOrderReference}}\",\n  \"date\": \"2026-10-21\",\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"supplier\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_SUPPLIER\"\n  },\n  \"purchaseType\": {\n    \"name\": \"REPLACE_WITH_SUPPORTED_GST_PURCHASE_TYPE\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100\n    }\n  ],\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"queue\": false,\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{purchaseOrderReference}}\",\n  \"date\": \"2026-10-21\",\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"supplier\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_SUPPLIER\"\n  },\n  \"purchaseType\": {\n    \"name\": \"REPLACE_WITH_SUPPORTED_GST_PURCHASE_TYPE\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100\n    }\n  ],\n  \"taxCalculation\": \"auto\",\n  \"pricingMode\": \"gstExclusive\",\n  \"queue\": false,\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","purchase-order-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"36a2cd4e-d3e2-42b0-bf5c-6e3fbeace76b","name":"SYNTHETIC — 200 created; native + stored-row proof","originalRequest":{"method":"GET","header":[],"url":""},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\r\n  \"success\": true,\r\n  \"data\": {\r\n    \"orderId\": 9001,\r\n    \"orderNumber\": \"SYN-PO-0001\",\r\n    \"orderReference\": \"AZPO-SYNTHETIC-001\",\r\n    \"date\": \"2026-10-21\",\r\n    \"voucherSeries\": {\r\n      \"code\": 7100,\r\n      \"name\": \"Synthetic Series\"\r\n    },\r\n    \"supplier\": {\r\n      \"code\": 7200,\r\n      \"name\": \"Synthetic Supplier\"\r\n    },\r\n    \"purchaseType\": {\r\n      \"code\": 7300,\r\n      \"name\": \"Synthetic Central Purchase\"\r\n    },\r\n    \"materialCenter\": {\r\n      \"code\": 7400,\r\n      \"name\": \"Synthetic Centre\"\r\n    },\r\n    \"taxCalculation\": \"auto\",\r\n    \"pricingMode\": \"gstExclusive\",\r\n    \"lines\": [\r\n      {\r\n        \"lineNumber\": 1,\r\n        \"item\": {\r\n          \"code\": 7500,\r\n          \"name\": \"Synthetic Item\"\r\n        },\r\n        \"unit\": {\r\n          \"code\": 7600,\r\n          \"name\": \"PCS\"\r\n        },\r\n        \"quantity\": 1,\r\n        \"rate\": 100,\r\n        \"netRate\": 100,\r\n        \"discountPercent\": null,\r\n        \"mrp\": 0,\r\n        \"description\": [],\r\n        \"taxableAmount\": 100,\r\n        \"cgst\": 0,\r\n        \"sgst\": 0,\r\n        \"igst\": 18,\r\n        \"amount\": 118,\r\n        \"discountShare\": 0,\r\n        \"pendingReferenceCode\": 10001,\r\n        \"pendingReferenceNumber\": \"PO0123456789ABCD-001\",\r\n        \"pendingQuantity\": -1,\r\n        \"dueDate\": \"2026-10-21\",\r\n        \"pendingRate\": 100\r\n      }\r\n    ],\r\n    \"billSundries\": [],\r\n    \"taxableAmount\": 100,\r\n    \"cgst\": 0,\r\n    \"sgst\": 0,\r\n    \"igst\": 18,\r\n    \"linesAmount\": 118,\r\n    \"totalAmount\": 118,\r\n    \"documentNumber\": null,\r\n    \"documentDate\": null,\r\n    \"narration\": null\r\n  },\r\n  \"metadata\": {\r\n    \"apiVersion\": \"v1\",\r\n    \"operation\": \"busy.purchase-orders.create\",\r\n    \"requestId\": \"synthetic-po-001\",\r\n    \"companyCode\": \"COMP0002\",\r\n    \"financialYear\": \"2026\",\r\n    \"outcome\": \"created\",\r\n    \"lineCount\": 1,\r\n    \"verification\": [\r\n      \"busyReadBack\",\r\n      \"savedRows\"\r\n    ],\r\n    \"elapsedMs\": 80,\r\n    \"executedAt\": \"2026-10-21T10:00:00Z\"\r\n  }\r\n}"},{"id":"6184d155-8b6d-4e4a-ab7d-153ead727908","name":"SYNTHETIC — 202 queued; BUSY result pending","originalRequest":{"method":"GET","header":[],"url":""},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\r\n  \"success\": true,\r\n  \"data\": null,\r\n  \"metadata\": {\r\n    \"apiVersion\": \"v1\",\r\n    \"operation\": \"busy.purchase-orders.create\",\r\n    \"requestId\": \"synthetic-po-001\",\r\n    \"jobId\": \"11111111111111111111111111111111\",\r\n    \"queued\": true,\r\n    \"status\": \"queued\"\r\n  }\r\n}"},{"id":"62e205bb-5d51-4410-81e1-8ad2199deecf","name":"SYNTHETIC — 400 INVALID_PARAMETER; bad quantity precision","originalRequest":{"method":"GET","header":[],"url":""},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\r\n  \"success\": false,\r\n  \"data\": null,\r\n  \"metadata\": {\r\n    \"error\": {\r\n      \"code\": \"INVALID_PARAMETER\",\r\n      \"message\": \"quantity supports at most 2 decimals, subject to the company's native precision.\",\r\n      \"field\": \"lines[0].quantity\"\r\n    },\r\n    \"requestId\": \"synthetic-po-001\",\r\n    \"apiVersion\": \"v1\"\r\n  }\r\n}"},{"id":"7ec3ac86-ced0-4f3c-907e-e16a246d1be5","name":"SYNTHETIC — 409 PURCHASE_ORDER_REFERENCE_TAKEN","originalRequest":{"method":"GET","header":[],"url":""},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\r\n  \"success\": false,\r\n  \"data\": null,\r\n  \"metadata\": {\r\n    \"error\": {\r\n      \"code\": \"PURCHASE_ORDER_REFERENCE_TAKEN\",\r\n      \"message\": \"A Purchase Order already holds this orderReference.\"\r\n    },\r\n    \"requestId\": \"synthetic-po-001\",\r\n    \"apiVersion\": \"v1\"\r\n  }\r\n}"},{"id":"2b3335ee-2bf2-4030-8136-32a2cbb5b4ed","name":"SYNTHETIC — 422 BUSY_WRITE_FAILED; no matching order","originalRequest":{"method":"GET","header":[],"url":""},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\r\n  \"success\": false,\r\n  \"data\": null,\r\n  \"metadata\": {\r\n    \"error\": {\r\n      \"code\": \"BUSY_WRITE_FAILED\",\r\n      \"message\": \"BUSY refused the Purchase Order; no matching order was found.\"\r\n    },\r\n    \"requestId\": \"synthetic-po-001\",\r\n    \"apiVersion\": \"v1\"\r\n  }\r\n}"},{"id":"921f7cbc-dff8-4289-ab5d-8ba3411f3a40","name":"SYNTHETIC — 502 BUSY_WRITE_UNVERIFIED; reconcile saved order","originalRequest":{"method":"GET","header":[],"url":""},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\r\n  \"success\": false,\r\n  \"data\": null,\r\n  \"metadata\": {\r\n    \"error\": {\r\n      \"code\": \"BUSY_WRITE_UNVERIFIED\",\r\n      \"message\": \"BUSY may have saved the Purchase Order, but verification failed. Check BUSY; do not resend.\",\r\n      \"details\": {\r\n        \"orderId\": 9002,\r\n        \"mismatchedFields\": [\r\n          \"lines[0].amount\"\r\n        ]\r\n      }\r\n    },\r\n    \"requestId\": \"synthetic-po-001\",\r\n    \"apiVersion\": \"v1\"\r\n  }\r\n}"},{"id":"e97bc0ea-1bdf-424d-bb28-abfb16e70887","name":"SYNTHETIC — 504 BUSY_WRITE_UNCERTAIN; do not resend","originalRequest":{"method":"GET","header":[],"url":""},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\r\n  \"success\": false,\r\n  \"data\": null,\r\n  \"metadata\": {\r\n    \"error\": {\r\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\r\n      \"message\": \"The Purchase Order outcome is uncertain. Reconcile in BUSY; do not resend.\",\r\n      \"details\": {\r\n        \"orderId\": 9003,\r\n        \"reconciliation\": \"notChecked\"\r\n      }\r\n    },\r\n    \"requestId\": \"synthetic-po-001\",\r\n    \"apiVersion\": \"v1\"\r\n  }\r\n}"}],"_postman_id":"d81a29c3-761e-4c83-a12e-2251ed35b2b0"},{"name":"⚠ BUSY material issue – create (writes to BUSY)","id":"066b64ac-915e-15c4-dc25-427407806482","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialIssueReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_MATERIAL_SERIES\"\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-issue-create","description":"<p><strong>Local source contract:</strong> POST {{baseUrl}}/api/v1/material-issue-create; operation <code>busy.material-issues.create</code>. Merged after public v0.0.17, which does not contain this route. The source/secondary-PC SQL and Access tests are recorded; installed service-account acceptance is pending. Cloud route/deployment is separate and not claimed.</p>\n<p><strong>Before Send:</strong> on this development PC use only COMP0001/COMP0002 FY2026, BUSY closed, a verified test-company backup and fresh synthetic fixtures. Set the correct automatic type-11 voucherSeries, existing party and materialCenter, and an untracked item with factor 1. Receipt may set an existing active salesman; Issue does not accept populated salesman. Replace every REPLACE_WITH_ name before sending. A registered party needs valid GST identity; billing/dealer values are derived from the party, not supplied. No GST modes, manual totals, tracking, allocation or settlement fields.</p>\n<p>The one-send confirmMutating=yes and loopback guards apply. If autoVoucherReferences=yes, a new materialIssueReference is generated before each allowed Send; otherwise set a fresh 1–60 character value. materialIssuePendingReview=yes is set before Send and stays set on no response, malformed/wrong response, 202, 502 or 504. Only verified 200 creation or an explicitly selected known pre-save refusal clears it. Never resend an uncertain write. A deliberate refusal may use materialIssueExpectedRefusal as exact STATUS ERROR_CODE; 502/504 cannot be selected as expected refusals. Optional X-Request-Id may be supplied for queue deduplication; it is distinct from materialReference.</p>\n<p><strong>Body:</strong> required companyCode, financialYear, materialReference, date, party, materialCenter and 1–100 lines; voucherSeries omission requires exactly one eligible series. Each line needs an existing item, positive main-unit quantity (up to 2 decimals and company precision) and explicit nonnegative rate (2 decimals, zero allowed). Optional listPrice, mrp, up to four positional descriptions, transport, GR/date, vehicle, station, narration, and strict boolean queue (default false). Native number is automatic. See docs/public/api/material-party-create.md for limits/provider text rules.</p>\n<p><strong>Outcomes:</strong> 200 has native BUSY read-back and independent saved-row proof; 202 is job acceptance only and keeps review pending. 400/409 examples are separate pre-save refusals. 502 BUSY_WRITE_UNVERIFIED may already be saved; 504 BUSY_WRITE_UNCERTAIN has unknown outcome. Inspect BUSY and write jobs before any new reference. All examples are synthetic, never live evidence. Trial/Pro/Max write plan applies.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Installed public v0.0.30 predates this merged source; these are documentation examples only. Do not Send until a newer candidate with this source is installed and the target BUSY series is verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialIssueReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false,\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialIssueReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false,\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","material-issue-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"962d8d1b-cc83-dc46-4f57-6abc7741279a","name":"SYNTHETIC — 200 created; native + stored-row proof","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialIssueReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_MATERIAL_SERIES\"\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-issue-create","description":"**Local source contract:** POST {{baseUrl}}/api/v1/material-issue-create; operation `busy.material-issues.create`. Merged after public v0.0.17, which does not contain this route. The source/secondary-PC SQL and Access tests are recorded; installed service-account acceptance is pending. Cloud route/deployment is separate and not claimed.\n\n**Before Send:** on this development PC use only COMP0001/COMP0002 FY2026, BUSY closed, a verified test-company backup and fresh synthetic fixtures. Set the correct automatic type-11 voucherSeries, existing party and materialCenter, and an untracked item with factor 1. Receipt may set an existing active salesman; Issue does not accept populated salesman. Replace every REPLACE_WITH_ name before sending. A registered party needs valid GST identity; billing/dealer values are derived from the party, not supplied. No GST modes, manual totals, tracking, allocation or settlement fields.\n\nThe one-send confirmMutating=yes and loopback guards apply. If autoVoucherReferences=yes, a new materialIssueReference is generated before each allowed Send; otherwise set a fresh 1–60 character value. materialIssuePendingReview=yes is set before Send and stays set on no response, malformed/wrong response, 202, 502 or 504. Only verified 200 creation or an explicitly selected known pre-save refusal clears it. Never resend an uncertain write. A deliberate refusal may use materialIssueExpectedRefusal as exact STATUS ERROR_CODE; 502/504 cannot be selected as expected refusals. Optional X-Request-Id may be supplied for queue deduplication; it is distinct from materialReference.\n\n**Body:** required companyCode, financialYear, materialReference, date, party, materialCenter and 1–100 lines; voucherSeries omission requires exactly one eligible series. Each line needs an existing item, positive main-unit quantity (up to 2 decimals and company precision) and explicit nonnegative rate (2 decimals, zero allowed). Optional listPrice, mrp, up to four positional descriptions, transport, GR/date, vehicle, station, narration, and strict boolean queue (default false). Native number is automatic. See docs/public/api/material-party-create.md for limits/provider text rules.\n\n**Outcomes:** 200 has native BUSY read-back and independent saved-row proof; 202 is job acceptance only and keeps review pending. 400/409 examples are separate pre-save refusals. 502 BUSY_WRITE_UNVERIFIED may already be saved; 504 BUSY_WRITE_UNCERTAIN has unknown outcome. Inspect BUSY and write jobs before any new reference. All examples are synthetic, never live evidence. Trial/Pro/Max write plan applies."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"voucherId\": 9001,\n    \"voucherNumber\": \"MI1\",\n    \"voucherType\": 11,\n    \"materialReference\": \"AZMI-SYNTHETIC-001\",\n    \"date\": \"2026-10-22\",\n    \"voucherSeries\": {\n      \"code\": 7100,\n      \"name\": \"Synthetic Auto Series\"\n    },\n    \"party\": {\n      \"code\": 7200,\n      \"name\": \"Synthetic Party\"\n    },\n    \"materialCenter\": {\n      \"code\": 7300,\n      \"name\": \"Synthetic Store\"\n    },\n    \"salesman\": null,\n    \"billing\": {\n      \"name\": \"Synthetic Party\",\n      \"address1\": \"\",\n      \"address2\": \"\",\n      \"address3\": \"\",\n      \"address4\": \"\",\n      \"mobile\": \"\",\n      \"email\": \"\",\n      \"panNumber\": \"\",\n      \"gstNumber\": \"\",\n      \"dealerType\": \"unregistered\",\n      \"source\": \"party\"\n    },\n    \"lines\": [\n      {\n        \"lineNumber\": 1,\n        \"item\": {\n          \"code\": 7400,\n          \"name\": \"Synthetic Item\"\n        },\n        \"unit\": {\n          \"code\": 7500,\n          \"name\": \"PCS\"\n        },\n        \"alternateUnit\": {\n          \"code\": 7500,\n          \"name\": \"PCS\"\n        },\n        \"conversionFactor\": 1,\n        \"quantity\": 1,\n        \"alternateQuantity\": 1,\n        \"rate\": 10,\n        \"alternateRate\": 10,\n        \"listPrice\": 10,\n        \"mrp\": 12,\n        \"amount\": 10,\n        \"description\": []\n      }\n    ],\n    \"totalMaterialValue\": 10,\n    \"transport\": null,\n    \"grNumber\": null,\n    \"grDate\": null,\n    \"vehicleNumber\": null,\n    \"station\": null,\n    \"narration\": null\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.material-issues.create\",\n    \"requestId\": \"synthetic-material-001\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 1,\n    \"verification\": [\n      \"busyReadBack\",\n      \"savedRows\"\n    ],\n    \"elapsedMs\": 80,\n    \"executedAt\": \"2026-10-22T10:00:00+00:00\"\n  }\n}"},{"id":"38560244-4126-cc05-29f3-6a68b1bd8043","name":"SYNTHETIC — 202 queued; not yet saved","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialIssueReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_MATERIAL_SERIES\"\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-issue-create","description":"**Local source contract:** POST {{baseUrl}}/api/v1/material-issue-create; operation `busy.material-issues.create`. Merged after public v0.0.17, which does not contain this route. The source/secondary-PC SQL and Access tests are recorded; installed service-account acceptance is pending. Cloud route/deployment is separate and not claimed.\n\n**Before Send:** on this development PC use only COMP0001/COMP0002 FY2026, BUSY closed, a verified test-company backup and fresh synthetic fixtures. Set the correct automatic type-11 voucherSeries, existing party and materialCenter, and an untracked item with factor 1. Receipt may set an existing active salesman; Issue does not accept populated salesman. Replace every REPLACE_WITH_ name before sending. A registered party needs valid GST identity; billing/dealer values are derived from the party, not supplied. No GST modes, manual totals, tracking, allocation or settlement fields.\n\nThe one-send confirmMutating=yes and loopback guards apply. If autoVoucherReferences=yes, a new materialIssueReference is generated before each allowed Send; otherwise set a fresh 1–60 character value. materialIssuePendingReview=yes is set before Send and stays set on no response, malformed/wrong response, 202, 502 or 504. Only verified 200 creation or an explicitly selected known pre-save refusal clears it. Never resend an uncertain write. A deliberate refusal may use materialIssueExpectedRefusal as exact STATUS ERROR_CODE; 502/504 cannot be selected as expected refusals. Optional X-Request-Id may be supplied for queue deduplication; it is distinct from materialReference.\n\n**Body:** required companyCode, financialYear, materialReference, date, party, materialCenter and 1–100 lines; voucherSeries omission requires exactly one eligible series. Each line needs an existing item, positive main-unit quantity (up to 2 decimals and company precision) and explicit nonnegative rate (2 decimals, zero allowed). Optional listPrice, mrp, up to four positional descriptions, transport, GR/date, vehicle, station, narration, and strict boolean queue (default false). Native number is automatic. See docs/public/api/material-party-create.md for limits/provider text rules.\n\n**Outcomes:** 200 has native BUSY read-back and independent saved-row proof; 202 is job acceptance only and keeps review pending. 400/409 examples are separate pre-save refusals. 502 BUSY_WRITE_UNVERIFIED may already be saved; 504 BUSY_WRITE_UNCERTAIN has unknown outcome. Inspect BUSY and write jobs before any new reference. All examples are synthetic, never live evidence. Trial/Pro/Max write plan applies."},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.material-issues.create\",\n    \"requestId\": \"synthetic-material-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"},{"id":"11dedb48-dcc3-df52-8e16-31d4fb308cc4","name":"SYNTHETIC — 400 INVALID_PARAMETER; bad quantity","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialIssueReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_MATERIAL_SERIES\"\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-issue-create","description":"**Local source contract:** POST {{baseUrl}}/api/v1/material-issue-create; operation `busy.material-issues.create`. Merged after public v0.0.17, which does not contain this route. The source/secondary-PC SQL and Access tests are recorded; installed service-account acceptance is pending. Cloud route/deployment is separate and not claimed.\n\n**Before Send:** on this development PC use only COMP0001/COMP0002 FY2026, BUSY closed, a verified test-company backup and fresh synthetic fixtures. Set the correct automatic type-11 voucherSeries, existing party and materialCenter, and an untracked item with factor 1. Receipt may set an existing active salesman; Issue does not accept populated salesman. Replace every REPLACE_WITH_ name before sending. A registered party needs valid GST identity; billing/dealer values are derived from the party, not supplied. No GST modes, manual totals, tracking, allocation or settlement fields.\n\nThe one-send confirmMutating=yes and loopback guards apply. If autoVoucherReferences=yes, a new materialIssueReference is generated before each allowed Send; otherwise set a fresh 1–60 character value. materialIssuePendingReview=yes is set before Send and stays set on no response, malformed/wrong response, 202, 502 or 504. Only verified 200 creation or an explicitly selected known pre-save refusal clears it. Never resend an uncertain write. A deliberate refusal may use materialIssueExpectedRefusal as exact STATUS ERROR_CODE; 502/504 cannot be selected as expected refusals. Optional X-Request-Id may be supplied for queue deduplication; it is distinct from materialReference.\n\n**Body:** required companyCode, financialYear, materialReference, date, party, materialCenter and 1–100 lines; voucherSeries omission requires exactly one eligible series. Each line needs an existing item, positive main-unit quantity (up to 2 decimals and company precision) and explicit nonnegative rate (2 decimals, zero allowed). Optional listPrice, mrp, up to four positional descriptions, transport, GR/date, vehicle, station, narration, and strict boolean queue (default false). Native number is automatic. See docs/public/api/material-party-create.md for limits/provider text rules.\n\n**Outcomes:** 200 has native BUSY read-back and independent saved-row proof; 202 is job acceptance only and keeps review pending. 400/409 examples are separate pre-save refusals. 502 BUSY_WRITE_UNVERIFIED may already be saved; 504 BUSY_WRITE_UNCERTAIN has unknown outcome. Inspect BUSY and write jobs before any new reference. All examples are synthetic, never live evidence. Trial/Pro/Max write plan applies."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"Quantity must be positive and fit the configured precision.\",\n      \"field\": \"lines[0].quantity\"\n    },\n    \"requestId\": \"synthetic-material-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"98f0c058-7c4f-cdae-6b3d-2e14a7bb3d9d","name":"SYNTHETIC — 409 MATERIAL_PARTY_REFERENCE_TAKEN","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialIssueReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_MATERIAL_SERIES\"\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-issue-create","description":"**Local source contract:** POST {{baseUrl}}/api/v1/material-issue-create; operation `busy.material-issues.create`. Merged after public v0.0.17, which does not contain this route. The source/secondary-PC SQL and Access tests are recorded; installed service-account acceptance is pending. Cloud route/deployment is separate and not claimed.\n\n**Before Send:** on this development PC use only COMP0001/COMP0002 FY2026, BUSY closed, a verified test-company backup and fresh synthetic fixtures. Set the correct automatic type-11 voucherSeries, existing party and materialCenter, and an untracked item with factor 1. Receipt may set an existing active salesman; Issue does not accept populated salesman. Replace every REPLACE_WITH_ name before sending. A registered party needs valid GST identity; billing/dealer values are derived from the party, not supplied. No GST modes, manual totals, tracking, allocation or settlement fields.\n\nThe one-send confirmMutating=yes and loopback guards apply. If autoVoucherReferences=yes, a new materialIssueReference is generated before each allowed Send; otherwise set a fresh 1–60 character value. materialIssuePendingReview=yes is set before Send and stays set on no response, malformed/wrong response, 202, 502 or 504. Only verified 200 creation or an explicitly selected known pre-save refusal clears it. Never resend an uncertain write. A deliberate refusal may use materialIssueExpectedRefusal as exact STATUS ERROR_CODE; 502/504 cannot be selected as expected refusals. Optional X-Request-Id may be supplied for queue deduplication; it is distinct from materialReference.\n\n**Body:** required companyCode, financialYear, materialReference, date, party, materialCenter and 1–100 lines; voucherSeries omission requires exactly one eligible series. Each line needs an existing item, positive main-unit quantity (up to 2 decimals and company precision) and explicit nonnegative rate (2 decimals, zero allowed). Optional listPrice, mrp, up to four positional descriptions, transport, GR/date, vehicle, station, narration, and strict boolean queue (default false). Native number is automatic. See docs/public/api/material-party-create.md for limits/provider text rules.\n\n**Outcomes:** 200 has native BUSY read-back and independent saved-row proof; 202 is job acceptance only and keeps review pending. 400/409 examples are separate pre-save refusals. 502 BUSY_WRITE_UNVERIFIED may already be saved; 504 BUSY_WRITE_UNCERTAIN has unknown outcome. Inspect BUSY and write jobs before any new reference. All examples are synthetic, never live evidence. Trial/Pro/Max write plan applies."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"MATERIAL_PARTY_REFERENCE_TAKEN\",\n      \"message\": \"A material voucher already holds this materialReference.\",\n      \"details\": {\n        \"voucherId\": 9002\n      }\n    },\n    \"requestId\": \"synthetic-material-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"a78409c7-e59b-ce37-e50f-90c44367ae53","name":"SYNTHETIC — 409 MATERIAL_PARTY_CONFIGURATION_CHANGED","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialIssueReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_MATERIAL_SERIES\"\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-issue-create","description":"**Local source contract:** POST {{baseUrl}}/api/v1/material-issue-create; operation `busy.material-issues.create`. Merged after public v0.0.17, which does not contain this route. The source/secondary-PC SQL and Access tests are recorded; installed service-account acceptance is pending. Cloud route/deployment is separate and not claimed.\n\n**Before Send:** on this development PC use only COMP0001/COMP0002 FY2026, BUSY closed, a verified test-company backup and fresh synthetic fixtures. Set the correct automatic type-11 voucherSeries, existing party and materialCenter, and an untracked item with factor 1. Receipt may set an existing active salesman; Issue does not accept populated salesman. Replace every REPLACE_WITH_ name before sending. A registered party needs valid GST identity; billing/dealer values are derived from the party, not supplied. No GST modes, manual totals, tracking, allocation or settlement fields.\n\nThe one-send confirmMutating=yes and loopback guards apply. If autoVoucherReferences=yes, a new materialIssueReference is generated before each allowed Send; otherwise set a fresh 1–60 character value. materialIssuePendingReview=yes is set before Send and stays set on no response, malformed/wrong response, 202, 502 or 504. Only verified 200 creation or an explicitly selected known pre-save refusal clears it. Never resend an uncertain write. A deliberate refusal may use materialIssueExpectedRefusal as exact STATUS ERROR_CODE; 502/504 cannot be selected as expected refusals. Optional X-Request-Id may be supplied for queue deduplication; it is distinct from materialReference.\n\n**Body:** required companyCode, financialYear, materialReference, date, party, materialCenter and 1–100 lines; voucherSeries omission requires exactly one eligible series. Each line needs an existing item, positive main-unit quantity (up to 2 decimals and company precision) and explicit nonnegative rate (2 decimals, zero allowed). Optional listPrice, mrp, up to four positional descriptions, transport, GR/date, vehicle, station, narration, and strict boolean queue (default false). Native number is automatic. See docs/public/api/material-party-create.md for limits/provider text rules.\n\n**Outcomes:** 200 has native BUSY read-back and independent saved-row proof; 202 is job acceptance only and keeps review pending. 400/409 examples are separate pre-save refusals. 502 BUSY_WRITE_UNVERIFIED may already be saved; 504 BUSY_WRITE_UNCERTAIN has unknown outcome. Inspect BUSY and write jobs before any new reference. All examples are synthetic, never live evidence. Trial/Pro/Max write plan applies."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"MATERIAL_PARTY_CONFIGURATION_CHANGED\",\n      \"message\": \"BUSY masters or settings changed during preflight. Review the configuration before a new attempt.\"\n    },\n    \"requestId\": \"synthetic-material-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"dc8be5de-0972-dd1d-6df6-182b31d2bb79","name":"SYNTHETIC — 502 BUSY_WRITE_UNVERIFIED; saved, reconcile","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialIssueReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_MATERIAL_SERIES\"\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-issue-create","description":"**Local source contract:** POST {{baseUrl}}/api/v1/material-issue-create; operation `busy.material-issues.create`. Merged after public v0.0.17, which does not contain this route. The source/secondary-PC SQL and Access tests are recorded; installed service-account acceptance is pending. Cloud route/deployment is separate and not claimed.\n\n**Before Send:** on this development PC use only COMP0001/COMP0002 FY2026, BUSY closed, a verified test-company backup and fresh synthetic fixtures. Set the correct automatic type-11 voucherSeries, existing party and materialCenter, and an untracked item with factor 1. Receipt may set an existing active salesman; Issue does not accept populated salesman. Replace every REPLACE_WITH_ name before sending. A registered party needs valid GST identity; billing/dealer values are derived from the party, not supplied. No GST modes, manual totals, tracking, allocation or settlement fields.\n\nThe one-send confirmMutating=yes and loopback guards apply. If autoVoucherReferences=yes, a new materialIssueReference is generated before each allowed Send; otherwise set a fresh 1–60 character value. materialIssuePendingReview=yes is set before Send and stays set on no response, malformed/wrong response, 202, 502 or 504. Only verified 200 creation or an explicitly selected known pre-save refusal clears it. Never resend an uncertain write. A deliberate refusal may use materialIssueExpectedRefusal as exact STATUS ERROR_CODE; 502/504 cannot be selected as expected refusals. Optional X-Request-Id may be supplied for queue deduplication; it is distinct from materialReference.\n\n**Body:** required companyCode, financialYear, materialReference, date, party, materialCenter and 1–100 lines; voucherSeries omission requires exactly one eligible series. Each line needs an existing item, positive main-unit quantity (up to 2 decimals and company precision) and explicit nonnegative rate (2 decimals, zero allowed). Optional listPrice, mrp, up to four positional descriptions, transport, GR/date, vehicle, station, narration, and strict boolean queue (default false). Native number is automatic. See docs/public/api/material-party-create.md for limits/provider text rules.\n\n**Outcomes:** 200 has native BUSY read-back and independent saved-row proof; 202 is job acceptance only and keeps review pending. 400/409 examples are separate pre-save refusals. 502 BUSY_WRITE_UNVERIFIED may already be saved; 504 BUSY_WRITE_UNCERTAIN has unknown outcome. Inspect BUSY and write jobs before any new reference. All examples are synthetic, never live evidence. Trial/Pro/Max write plan applies."},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNVERIFIED\",\n      \"message\": \"BUSY saved the material voucher but read-back differs; inspect the saved reference.\",\n      \"details\": {\n        \"voucherId\": 9003,\n        \"mismatchedFields\": [\n          \"lines[0].amount\"\n        ]\n      }\n    },\n    \"requestId\": \"synthetic-material-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"1d9277f1-13d3-c0d3-f1ff-72f80492da34","name":"SYNTHETIC — 504 BUSY_WRITE_UNCERTAIN; do not resend","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialIssueReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_MATERIAL_SERIES\"\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-issue-create","description":"**Local source contract:** POST {{baseUrl}}/api/v1/material-issue-create; operation `busy.material-issues.create`. Merged after public v0.0.17, which does not contain this route. The source/secondary-PC SQL and Access tests are recorded; installed service-account acceptance is pending. Cloud route/deployment is separate and not claimed.\n\n**Before Send:** on this development PC use only COMP0001/COMP0002 FY2026, BUSY closed, a verified test-company backup and fresh synthetic fixtures. Set the correct automatic type-11 voucherSeries, existing party and materialCenter, and an untracked item with factor 1. Receipt may set an existing active salesman; Issue does not accept populated salesman. Replace every REPLACE_WITH_ name before sending. A registered party needs valid GST identity; billing/dealer values are derived from the party, not supplied. No GST modes, manual totals, tracking, allocation or settlement fields.\n\nThe one-send confirmMutating=yes and loopback guards apply. If autoVoucherReferences=yes, a new materialIssueReference is generated before each allowed Send; otherwise set a fresh 1–60 character value. materialIssuePendingReview=yes is set before Send and stays set on no response, malformed/wrong response, 202, 502 or 504. Only verified 200 creation or an explicitly selected known pre-save refusal clears it. Never resend an uncertain write. A deliberate refusal may use materialIssueExpectedRefusal as exact STATUS ERROR_CODE; 502/504 cannot be selected as expected refusals. Optional X-Request-Id may be supplied for queue deduplication; it is distinct from materialReference.\n\n**Body:** required companyCode, financialYear, materialReference, date, party, materialCenter and 1–100 lines; voucherSeries omission requires exactly one eligible series. Each line needs an existing item, positive main-unit quantity (up to 2 decimals and company precision) and explicit nonnegative rate (2 decimals, zero allowed). Optional listPrice, mrp, up to four positional descriptions, transport, GR/date, vehicle, station, narration, and strict boolean queue (default false). Native number is automatic. See docs/public/api/material-party-create.md for limits/provider text rules.\n\n**Outcomes:** 200 has native BUSY read-back and independent saved-row proof; 202 is job acceptance only and keeps review pending. 400/409 examples are separate pre-save refusals. 502 BUSY_WRITE_UNVERIFIED may already be saved; 504 BUSY_WRITE_UNCERTAIN has unknown outcome. Inspect BUSY and write jobs before any new reference. All examples are synthetic, never live evidence. Trial/Pro/Max write plan applies."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"The material voucher outcome is uncertain; reconcile before a new attempt.\",\n      \"details\": {\n        \"reconciliation\": \"notChecked\"\n      }\n    },\n    \"requestId\": \"synthetic-material-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"066b64ac-915e-15c4-dc25-427407806482"},{"name":"⚠ BUSY material receipt – create (writes to BUSY)","id":"77120bc8-2d11-4a25-5c16-65e5234f690e","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialReceiptReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_MATERIAL_SERIES\"\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"salesman\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_SALESMAN\"\n  },\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-receipt-create","description":"<p><strong>Local source contract:</strong> POST {{baseUrl}}/api/v1/material-receipt-create; operation <code>busy.material-receipts.create</code>. Merged after public v0.0.17, which does not contain this route. The source/secondary-PC SQL and Access tests are recorded; installed service-account acceptance is pending. Cloud route/deployment is separate and not claimed.</p>\n<p><strong>Before Send:</strong> on this development PC use only COMP0001/COMP0002 FY2026, BUSY closed, a verified test-company backup and fresh synthetic fixtures. Set the correct automatic type-4 voucherSeries, existing party and materialCenter, and an untracked item with factor 1. Receipt may set an existing active salesman; Issue does not accept populated salesman. Replace every REPLACE_WITH_ name before sending. A registered party needs valid GST identity; billing/dealer values are derived from the party, not supplied. No GST modes, manual totals, tracking, allocation or settlement fields.</p>\n<p>The one-send confirmMutating=yes and loopback guards apply. If autoVoucherReferences=yes, a new materialReceiptReference is generated before each allowed Send; otherwise set a fresh 1–60 character value. materialReceiptPendingReview=yes is set before Send and stays set on no response, malformed/wrong response, 202, 502 or 504. Only verified 200 creation or an explicitly selected known pre-save refusal clears it. Never resend an uncertain write. A deliberate refusal may use materialReceiptExpectedRefusal as exact STATUS ERROR_CODE; 502/504 cannot be selected as expected refusals. Optional X-Request-Id may be supplied for queue deduplication; it is distinct from materialReference.</p>\n<p><strong>Body:</strong> required companyCode, financialYear, materialReference, date, party, materialCenter and 1–100 lines; voucherSeries omission requires exactly one eligible series. Each line needs an existing item, positive main-unit quantity (up to 2 decimals and company precision) and explicit nonnegative rate (2 decimals, zero allowed). Optional listPrice, mrp, up to four positional descriptions, transport, GR/date, vehicle, station, narration, and strict boolean queue (default false). Native number is automatic. See docs/public/api/material-party-create.md for limits/provider text rules.</p>\n<p><strong>Outcomes:</strong> 200 has native BUSY read-back and independent saved-row proof; 202 is job acceptance only and keeps review pending. 400/409 examples are separate pre-save refusals. 502 BUSY_WRITE_UNVERIFIED may already be saved; 504 BUSY_WRITE_UNCERTAIN has unknown outcome. Inspect BUSY and write jobs before any new reference. All examples are synthetic, never live evidence. Trial/Pro/Max write plan applies.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Installed public v0.0.30 predates this merged source; these are documentation examples only. Do not Send until a newer candidate with this source is installed and the target BUSY series is verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialReceiptReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"salesman\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_SALESMAN\"\n  },\n  \"queue\": false,\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialReceiptReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"salesman\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_SALESMAN\"\n  },\n  \"queue\": false,\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","material-receipt-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"1cce0519-4634-a444-ea2b-886cdf23b598","name":"SYNTHETIC — 200 created; native + stored-row proof","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialReceiptReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_MATERIAL_SERIES\"\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"salesman\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_SALESMAN\"\n  },\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-receipt-create","description":"**Local source contract:** POST {{baseUrl}}/api/v1/material-receipt-create; operation `busy.material-receipts.create`. Merged after public v0.0.17, which does not contain this route. The source/secondary-PC SQL and Access tests are recorded; installed service-account acceptance is pending. Cloud route/deployment is separate and not claimed.\n\n**Before Send:** on this development PC use only COMP0001/COMP0002 FY2026, BUSY closed, a verified test-company backup and fresh synthetic fixtures. Set the correct automatic type-4 voucherSeries, existing party and materialCenter, and an untracked item with factor 1. Receipt may set an existing active salesman; Issue does not accept populated salesman. Replace every REPLACE_WITH_ name before sending. A registered party needs valid GST identity; billing/dealer values are derived from the party, not supplied. No GST modes, manual totals, tracking, allocation or settlement fields.\n\nThe one-send confirmMutating=yes and loopback guards apply. If autoVoucherReferences=yes, a new materialReceiptReference is generated before each allowed Send; otherwise set a fresh 1–60 character value. materialReceiptPendingReview=yes is set before Send and stays set on no response, malformed/wrong response, 202, 502 or 504. Only verified 200 creation or an explicitly selected known pre-save refusal clears it. Never resend an uncertain write. A deliberate refusal may use materialReceiptExpectedRefusal as exact STATUS ERROR_CODE; 502/504 cannot be selected as expected refusals. Optional X-Request-Id may be supplied for queue deduplication; it is distinct from materialReference.\n\n**Body:** required companyCode, financialYear, materialReference, date, party, materialCenter and 1–100 lines; voucherSeries omission requires exactly one eligible series. Each line needs an existing item, positive main-unit quantity (up to 2 decimals and company precision) and explicit nonnegative rate (2 decimals, zero allowed). Optional listPrice, mrp, up to four positional descriptions, transport, GR/date, vehicle, station, narration, and strict boolean queue (default false). Native number is automatic. See docs/public/api/material-party-create.md for limits/provider text rules.\n\n**Outcomes:** 200 has native BUSY read-back and independent saved-row proof; 202 is job acceptance only and keeps review pending. 400/409 examples are separate pre-save refusals. 502 BUSY_WRITE_UNVERIFIED may already be saved; 504 BUSY_WRITE_UNCERTAIN has unknown outcome. Inspect BUSY and write jobs before any new reference. All examples are synthetic, never live evidence. Trial/Pro/Max write plan applies."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"voucherId\": 9001,\n    \"voucherNumber\": \"MR1\",\n    \"voucherType\": 4,\n    \"materialReference\": \"AZMR-SYNTHETIC-001\",\n    \"date\": \"2026-10-22\",\n    \"voucherSeries\": {\n      \"code\": 7100,\n      \"name\": \"Synthetic Auto Series\"\n    },\n    \"party\": {\n      \"code\": 7200,\n      \"name\": \"Synthetic Party\"\n    },\n    \"materialCenter\": {\n      \"code\": 7300,\n      \"name\": \"Synthetic Store\"\n    },\n    \"salesman\": {\n      \"code\": 7600,\n      \"name\": \"Synthetic Salesman\"\n    },\n    \"billing\": {\n      \"name\": \"Synthetic Party\",\n      \"address1\": \"\",\n      \"address2\": \"\",\n      \"address3\": \"\",\n      \"address4\": \"\",\n      \"mobile\": \"\",\n      \"email\": \"\",\n      \"panNumber\": \"\",\n      \"gstNumber\": \"\",\n      \"dealerType\": \"unregistered\",\n      \"source\": \"party\"\n    },\n    \"lines\": [\n      {\n        \"lineNumber\": 1,\n        \"item\": {\n          \"code\": 7400,\n          \"name\": \"Synthetic Item\"\n        },\n        \"unit\": {\n          \"code\": 7500,\n          \"name\": \"PCS\"\n        },\n        \"alternateUnit\": {\n          \"code\": 7500,\n          \"name\": \"PCS\"\n        },\n        \"conversionFactor\": 1,\n        \"quantity\": 1,\n        \"alternateQuantity\": 1,\n        \"rate\": 10,\n        \"alternateRate\": 10,\n        \"listPrice\": 10,\n        \"mrp\": 12,\n        \"amount\": 10,\n        \"description\": []\n      }\n    ],\n    \"totalMaterialValue\": 10,\n    \"transport\": null,\n    \"grNumber\": null,\n    \"grDate\": null,\n    \"vehicleNumber\": null,\n    \"station\": null,\n    \"narration\": null\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.material-receipts.create\",\n    \"requestId\": \"synthetic-material-001\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 1,\n    \"verification\": [\n      \"busyReadBack\",\n      \"savedRows\"\n    ],\n    \"elapsedMs\": 80,\n    \"executedAt\": \"2026-10-22T10:00:00+00:00\"\n  }\n}"},{"id":"a4157e0b-22fa-6fd8-80e3-7bf8ad827640","name":"SYNTHETIC — 202 queued; not yet saved","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialReceiptReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_MATERIAL_SERIES\"\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"salesman\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_SALESMAN\"\n  },\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-receipt-create","description":"**Local source contract:** POST {{baseUrl}}/api/v1/material-receipt-create; operation `busy.material-receipts.create`. Merged after public v0.0.17, which does not contain this route. The source/secondary-PC SQL and Access tests are recorded; installed service-account acceptance is pending. Cloud route/deployment is separate and not claimed.\n\n**Before Send:** on this development PC use only COMP0001/COMP0002 FY2026, BUSY closed, a verified test-company backup and fresh synthetic fixtures. Set the correct automatic type-4 voucherSeries, existing party and materialCenter, and an untracked item with factor 1. Receipt may set an existing active salesman; Issue does not accept populated salesman. Replace every REPLACE_WITH_ name before sending. A registered party needs valid GST identity; billing/dealer values are derived from the party, not supplied. No GST modes, manual totals, tracking, allocation or settlement fields.\n\nThe one-send confirmMutating=yes and loopback guards apply. If autoVoucherReferences=yes, a new materialReceiptReference is generated before each allowed Send; otherwise set a fresh 1–60 character value. materialReceiptPendingReview=yes is set before Send and stays set on no response, malformed/wrong response, 202, 502 or 504. Only verified 200 creation or an explicitly selected known pre-save refusal clears it. Never resend an uncertain write. A deliberate refusal may use materialReceiptExpectedRefusal as exact STATUS ERROR_CODE; 502/504 cannot be selected as expected refusals. Optional X-Request-Id may be supplied for queue deduplication; it is distinct from materialReference.\n\n**Body:** required companyCode, financialYear, materialReference, date, party, materialCenter and 1–100 lines; voucherSeries omission requires exactly one eligible series. Each line needs an existing item, positive main-unit quantity (up to 2 decimals and company precision) and explicit nonnegative rate (2 decimals, zero allowed). Optional listPrice, mrp, up to four positional descriptions, transport, GR/date, vehicle, station, narration, and strict boolean queue (default false). Native number is automatic. See docs/public/api/material-party-create.md for limits/provider text rules.\n\n**Outcomes:** 200 has native BUSY read-back and independent saved-row proof; 202 is job acceptance only and keeps review pending. 400/409 examples are separate pre-save refusals. 502 BUSY_WRITE_UNVERIFIED may already be saved; 504 BUSY_WRITE_UNCERTAIN has unknown outcome. Inspect BUSY and write jobs before any new reference. All examples are synthetic, never live evidence. Trial/Pro/Max write plan applies."},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.material-receipts.create\",\n    \"requestId\": \"synthetic-material-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"},{"id":"fec715f9-51a6-58ed-11c6-3f898b62657d","name":"SYNTHETIC — 400 INVALID_PARAMETER; bad quantity","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialReceiptReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_MATERIAL_SERIES\"\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"salesman\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_SALESMAN\"\n  },\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-receipt-create","description":"**Local source contract:** POST {{baseUrl}}/api/v1/material-receipt-create; operation `busy.material-receipts.create`. Merged after public v0.0.17, which does not contain this route. The source/secondary-PC SQL and Access tests are recorded; installed service-account acceptance is pending. Cloud route/deployment is separate and not claimed.\n\n**Before Send:** on this development PC use only COMP0001/COMP0002 FY2026, BUSY closed, a verified test-company backup and fresh synthetic fixtures. Set the correct automatic type-4 voucherSeries, existing party and materialCenter, and an untracked item with factor 1. Receipt may set an existing active salesman; Issue does not accept populated salesman. Replace every REPLACE_WITH_ name before sending. A registered party needs valid GST identity; billing/dealer values are derived from the party, not supplied. No GST modes, manual totals, tracking, allocation or settlement fields.\n\nThe one-send confirmMutating=yes and loopback guards apply. If autoVoucherReferences=yes, a new materialReceiptReference is generated before each allowed Send; otherwise set a fresh 1–60 character value. materialReceiptPendingReview=yes is set before Send and stays set on no response, malformed/wrong response, 202, 502 or 504. Only verified 200 creation or an explicitly selected known pre-save refusal clears it. Never resend an uncertain write. A deliberate refusal may use materialReceiptExpectedRefusal as exact STATUS ERROR_CODE; 502/504 cannot be selected as expected refusals. Optional X-Request-Id may be supplied for queue deduplication; it is distinct from materialReference.\n\n**Body:** required companyCode, financialYear, materialReference, date, party, materialCenter and 1–100 lines; voucherSeries omission requires exactly one eligible series. Each line needs an existing item, positive main-unit quantity (up to 2 decimals and company precision) and explicit nonnegative rate (2 decimals, zero allowed). Optional listPrice, mrp, up to four positional descriptions, transport, GR/date, vehicle, station, narration, and strict boolean queue (default false). Native number is automatic. See docs/public/api/material-party-create.md for limits/provider text rules.\n\n**Outcomes:** 200 has native BUSY read-back and independent saved-row proof; 202 is job acceptance only and keeps review pending. 400/409 examples are separate pre-save refusals. 502 BUSY_WRITE_UNVERIFIED may already be saved; 504 BUSY_WRITE_UNCERTAIN has unknown outcome. Inspect BUSY and write jobs before any new reference. All examples are synthetic, never live evidence. Trial/Pro/Max write plan applies."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"Quantity must be positive and fit the configured precision.\",\n      \"field\": \"lines[0].quantity\"\n    },\n    \"requestId\": \"synthetic-material-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"1772fc60-5c24-884e-9c74-288b66957345","name":"SYNTHETIC — 409 MATERIAL_PARTY_REFERENCE_TAKEN","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialReceiptReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_MATERIAL_SERIES\"\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"salesman\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_SALESMAN\"\n  },\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-receipt-create","description":"**Local source contract:** POST {{baseUrl}}/api/v1/material-receipt-create; operation `busy.material-receipts.create`. Merged after public v0.0.17, which does not contain this route. The source/secondary-PC SQL and Access tests are recorded; installed service-account acceptance is pending. Cloud route/deployment is separate and not claimed.\n\n**Before Send:** on this development PC use only COMP0001/COMP0002 FY2026, BUSY closed, a verified test-company backup and fresh synthetic fixtures. Set the correct automatic type-4 voucherSeries, existing party and materialCenter, and an untracked item with factor 1. Receipt may set an existing active salesman; Issue does not accept populated salesman. Replace every REPLACE_WITH_ name before sending. A registered party needs valid GST identity; billing/dealer values are derived from the party, not supplied. No GST modes, manual totals, tracking, allocation or settlement fields.\n\nThe one-send confirmMutating=yes and loopback guards apply. If autoVoucherReferences=yes, a new materialReceiptReference is generated before each allowed Send; otherwise set a fresh 1–60 character value. materialReceiptPendingReview=yes is set before Send and stays set on no response, malformed/wrong response, 202, 502 or 504. Only verified 200 creation or an explicitly selected known pre-save refusal clears it. Never resend an uncertain write. A deliberate refusal may use materialReceiptExpectedRefusal as exact STATUS ERROR_CODE; 502/504 cannot be selected as expected refusals. Optional X-Request-Id may be supplied for queue deduplication; it is distinct from materialReference.\n\n**Body:** required companyCode, financialYear, materialReference, date, party, materialCenter and 1–100 lines; voucherSeries omission requires exactly one eligible series. Each line needs an existing item, positive main-unit quantity (up to 2 decimals and company precision) and explicit nonnegative rate (2 decimals, zero allowed). Optional listPrice, mrp, up to four positional descriptions, transport, GR/date, vehicle, station, narration, and strict boolean queue (default false). Native number is automatic. See docs/public/api/material-party-create.md for limits/provider text rules.\n\n**Outcomes:** 200 has native BUSY read-back and independent saved-row proof; 202 is job acceptance only and keeps review pending. 400/409 examples are separate pre-save refusals. 502 BUSY_WRITE_UNVERIFIED may already be saved; 504 BUSY_WRITE_UNCERTAIN has unknown outcome. Inspect BUSY and write jobs before any new reference. All examples are synthetic, never live evidence. Trial/Pro/Max write plan applies."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"MATERIAL_PARTY_REFERENCE_TAKEN\",\n      \"message\": \"A material voucher already holds this materialReference.\",\n      \"details\": {\n        \"voucherId\": 9002\n      }\n    },\n    \"requestId\": \"synthetic-material-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"f19ba3e3-2023-f6a1-f8a9-ea16c58d81f4","name":"SYNTHETIC — 409 MATERIAL_PARTY_CONFIGURATION_CHANGED","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialReceiptReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_MATERIAL_SERIES\"\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"salesman\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_SALESMAN\"\n  },\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-receipt-create","description":"**Local source contract:** POST {{baseUrl}}/api/v1/material-receipt-create; operation `busy.material-receipts.create`. Merged after public v0.0.17, which does not contain this route. The source/secondary-PC SQL and Access tests are recorded; installed service-account acceptance is pending. Cloud route/deployment is separate and not claimed.\n\n**Before Send:** on this development PC use only COMP0001/COMP0002 FY2026, BUSY closed, a verified test-company backup and fresh synthetic fixtures. Set the correct automatic type-4 voucherSeries, existing party and materialCenter, and an untracked item with factor 1. Receipt may set an existing active salesman; Issue does not accept populated salesman. Replace every REPLACE_WITH_ name before sending. A registered party needs valid GST identity; billing/dealer values are derived from the party, not supplied. No GST modes, manual totals, tracking, allocation or settlement fields.\n\nThe one-send confirmMutating=yes and loopback guards apply. If autoVoucherReferences=yes, a new materialReceiptReference is generated before each allowed Send; otherwise set a fresh 1–60 character value. materialReceiptPendingReview=yes is set before Send and stays set on no response, malformed/wrong response, 202, 502 or 504. Only verified 200 creation or an explicitly selected known pre-save refusal clears it. Never resend an uncertain write. A deliberate refusal may use materialReceiptExpectedRefusal as exact STATUS ERROR_CODE; 502/504 cannot be selected as expected refusals. Optional X-Request-Id may be supplied for queue deduplication; it is distinct from materialReference.\n\n**Body:** required companyCode, financialYear, materialReference, date, party, materialCenter and 1–100 lines; voucherSeries omission requires exactly one eligible series. Each line needs an existing item, positive main-unit quantity (up to 2 decimals and company precision) and explicit nonnegative rate (2 decimals, zero allowed). Optional listPrice, mrp, up to four positional descriptions, transport, GR/date, vehicle, station, narration, and strict boolean queue (default false). Native number is automatic. See docs/public/api/material-party-create.md for limits/provider text rules.\n\n**Outcomes:** 200 has native BUSY read-back and independent saved-row proof; 202 is job acceptance only and keeps review pending. 400/409 examples are separate pre-save refusals. 502 BUSY_WRITE_UNVERIFIED may already be saved; 504 BUSY_WRITE_UNCERTAIN has unknown outcome. Inspect BUSY and write jobs before any new reference. All examples are synthetic, never live evidence. Trial/Pro/Max write plan applies."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"MATERIAL_PARTY_CONFIGURATION_CHANGED\",\n      \"message\": \"BUSY masters or settings changed during preflight. Review the configuration before a new attempt.\"\n    },\n    \"requestId\": \"synthetic-material-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"a9437bb1-f44c-d1bb-52e5-698ba988c82a","name":"SYNTHETIC — 502 BUSY_WRITE_UNVERIFIED; saved, reconcile","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialReceiptReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_MATERIAL_SERIES\"\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"salesman\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_SALESMAN\"\n  },\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-receipt-create","description":"**Local source contract:** POST {{baseUrl}}/api/v1/material-receipt-create; operation `busy.material-receipts.create`. Merged after public v0.0.17, which does not contain this route. The source/secondary-PC SQL and Access tests are recorded; installed service-account acceptance is pending. Cloud route/deployment is separate and not claimed.\n\n**Before Send:** on this development PC use only COMP0001/COMP0002 FY2026, BUSY closed, a verified test-company backup and fresh synthetic fixtures. Set the correct automatic type-4 voucherSeries, existing party and materialCenter, and an untracked item with factor 1. Receipt may set an existing active salesman; Issue does not accept populated salesman. Replace every REPLACE_WITH_ name before sending. A registered party needs valid GST identity; billing/dealer values are derived from the party, not supplied. No GST modes, manual totals, tracking, allocation or settlement fields.\n\nThe one-send confirmMutating=yes and loopback guards apply. If autoVoucherReferences=yes, a new materialReceiptReference is generated before each allowed Send; otherwise set a fresh 1–60 character value. materialReceiptPendingReview=yes is set before Send and stays set on no response, malformed/wrong response, 202, 502 or 504. Only verified 200 creation or an explicitly selected known pre-save refusal clears it. Never resend an uncertain write. A deliberate refusal may use materialReceiptExpectedRefusal as exact STATUS ERROR_CODE; 502/504 cannot be selected as expected refusals. Optional X-Request-Id may be supplied for queue deduplication; it is distinct from materialReference.\n\n**Body:** required companyCode, financialYear, materialReference, date, party, materialCenter and 1–100 lines; voucherSeries omission requires exactly one eligible series. Each line needs an existing item, positive main-unit quantity (up to 2 decimals and company precision) and explicit nonnegative rate (2 decimals, zero allowed). Optional listPrice, mrp, up to four positional descriptions, transport, GR/date, vehicle, station, narration, and strict boolean queue (default false). Native number is automatic. See docs/public/api/material-party-create.md for limits/provider text rules.\n\n**Outcomes:** 200 has native BUSY read-back and independent saved-row proof; 202 is job acceptance only and keeps review pending. 400/409 examples are separate pre-save refusals. 502 BUSY_WRITE_UNVERIFIED may already be saved; 504 BUSY_WRITE_UNCERTAIN has unknown outcome. Inspect BUSY and write jobs before any new reference. All examples are synthetic, never live evidence. Trial/Pro/Max write plan applies."},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNVERIFIED\",\n      \"message\": \"BUSY saved the material voucher but read-back differs; inspect the saved reference.\",\n      \"details\": {\n        \"voucherId\": 9003,\n        \"mismatchedFields\": [\n          \"lines[0].amount\"\n        ]\n      }\n    },\n    \"requestId\": \"synthetic-material-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"2c3226ee-5e71-5958-eeff-11ab33690bb6","name":"SYNTHETIC — 504 BUSY_WRITE_UNCERTAIN; do not resend","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialReceiptReference}}\",\n  \"date\": \"2026-10-22\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_MATERIAL_SERIES\"\n  },\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"REPLACE_WITH_MATERIAL_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"salesman\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_SALESMAN\"\n  },\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/material-receipt-create","description":"**Local source contract:** POST {{baseUrl}}/api/v1/material-receipt-create; operation `busy.material-receipts.create`. Merged after public v0.0.17, which does not contain this route. The source/secondary-PC SQL and Access tests are recorded; installed service-account acceptance is pending. Cloud route/deployment is separate and not claimed.\n\n**Before Send:** on this development PC use only COMP0001/COMP0002 FY2026, BUSY closed, a verified test-company backup and fresh synthetic fixtures. Set the correct automatic type-4 voucherSeries, existing party and materialCenter, and an untracked item with factor 1. Receipt may set an existing active salesman; Issue does not accept populated salesman. Replace every REPLACE_WITH_ name before sending. A registered party needs valid GST identity; billing/dealer values are derived from the party, not supplied. No GST modes, manual totals, tracking, allocation or settlement fields.\n\nThe one-send confirmMutating=yes and loopback guards apply. If autoVoucherReferences=yes, a new materialReceiptReference is generated before each allowed Send; otherwise set a fresh 1–60 character value. materialReceiptPendingReview=yes is set before Send and stays set on no response, malformed/wrong response, 202, 502 or 504. Only verified 200 creation or an explicitly selected known pre-save refusal clears it. Never resend an uncertain write. A deliberate refusal may use materialReceiptExpectedRefusal as exact STATUS ERROR_CODE; 502/504 cannot be selected as expected refusals. Optional X-Request-Id may be supplied for queue deduplication; it is distinct from materialReference.\n\n**Body:** required companyCode, financialYear, materialReference, date, party, materialCenter and 1–100 lines; voucherSeries omission requires exactly one eligible series. Each line needs an existing item, positive main-unit quantity (up to 2 decimals and company precision) and explicit nonnegative rate (2 decimals, zero allowed). Optional listPrice, mrp, up to four positional descriptions, transport, GR/date, vehicle, station, narration, and strict boolean queue (default false). Native number is automatic. See docs/public/api/material-party-create.md for limits/provider text rules.\n\n**Outcomes:** 200 has native BUSY read-back and independent saved-row proof; 202 is job acceptance only and keeps review pending. 400/409 examples are separate pre-save refusals. 502 BUSY_WRITE_UNVERIFIED may already be saved; 504 BUSY_WRITE_UNCERTAIN has unknown outcome. Inspect BUSY and write jobs before any new reference. All examples are synthetic, never live evidence. Trial/Pro/Max write plan applies."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"The material voucher outcome is uncertain; reconcile before a new attempt.\",\n      \"details\": {\n        \"reconciliation\": \"notChecked\"\n      }\n    },\n    \"requestId\": \"synthetic-material-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"77120bc8-2d11-4a25-5c16-65e5234f690e"},{"name":"⚠ BUSY stock journal – create (writes to BUSY)","id":"0462e5af-24d0-03c6-89b8-00ebe1841777","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"journalReference\": \"{{stockJournalReference}}\",\n  \"date\": \"2026-10-20\",\n  \"voucherSeries\": {\n    \"name\": \"REPLACE_WITH_AUTOMATIC_STOCK_JOURNAL_SERIES\"\n  },\n  \"productionMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_PRODUCTION_CENTRE\"\n  },\n  \"productionLines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_PRODUCTION_ITEM\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 1.02,\n      \"description\": [\n        \"Synthetic finished item\",\n        \"\",\n        \"Third position\"\n      ]\n    }\n  ],\n  \"consumptionMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_CONSUMPTION_CENTRE\"\n  },\n  \"consumptionLines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_CONSUMPTION_ITEM\"\n      },\n      \"quantity\": 2,\n      \"rate\": 0.5\n    }\n  ],\n  \"narration\": \"Synthetic stock journal\",\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/stock-journal-create","description":"<p><strong>Local source contract:</strong> POST {{baseUrl}}/api/v1/stock-journal-create, operation <code>busy.stock-journals.create</code>. This is a BUSY write. Merged source and secondary-PC SQL/Access native/interactive evidence exist; installed AIZenySvc acceptance is tracked separately. Cloud Relay is not deployed by this collection entry.</p>\n<p><strong>Before Send:</strong> only loopback COMP0001/COMP0002 FY2026 on this development PC, BUSY closed, verified test-company backup, fresh synthetic reference and existing untracked factor-one items/centres/automatic type-8 series. Replace every REPLACE_WITH_ placeholder. Confirm with confirmMutating=yes for one send. A pending or uncertain send locks this request through stockJournalPendingReview=yes; reconcile read-only, never blindly resend, including with a new reference. autoVoucherReferences=yes generates a fresh stockJournalReference; otherwise set one manually. Optional X-Request-Id is for queue deduplication, distinct from journalReference.</p>\n<p><strong>Shapes:</strong> The displayed body is mixed. For production-only remove consumptionLines and consumptionMaterialCenter. For consumption-only remove productionLines and productionMaterialCenter. Positive quantities describe their own side. Both lists may use the same centre. At least one line, at most 100 combined. Omitted/false queue waits for verified 200; true accepts a durable job at 202 and requires final job verification.</p>\n<p><strong>Fields:</strong> companyCode, financialYear, journalReference (1–60), date (YYYY-MM-DD within FY) and one populated line side are required. Each populated side requires its material centre. Every line requires item {code OR name}, positive main-unit quantity (up to 3 decimals and configured precision) and nonnegative rate (up to 2 decimals). Optional voucherSeries (omission needs exactly one eligible), positional description (1–4 entries, &lt;=40 chars), narration (&lt;=94) and strict boolean queue. No tracking, caller numbering, GST modes, sundries or arbitrary metadata. SQL text must fit Latin-1; Access supports approved Unicode scope. See docs/public/api/stock-journal-create.md.</p>\n<p><strong>Outcome:</strong> verified 200 includes native BUSY read-back and independent saved-row proof; 202 is queue acceptance only. Expected pre-save refusal can be selected using stockJournalExpectedRefusal as exact STATUS ERROR_CODE; ordinary success never accepts a refusal. 502 BUSY_WRITE_UNVERIFIED may already be saved and can include details.journalId/mismatchedFields. 504 BUSY_WRITE_UNCERTAIN may include journalId/reconciliation. Keep stockJournalPendingReview and investigate; do not retry. All examples are synthetic. Trial/Pro/Max write plan applies.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Installed public v0.0.30 predates this merged source; these are documentation examples only. Do not Send until a newer candidate with this source is installed and the target BUSY series is verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"journalReference\": \"{{stockJournalReference}}\",\n  \"date\": \"2026-10-20\",\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"productionMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_PRODUCTION_CENTRE\"\n  },\n  \"productionLines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_PRODUCTION_ITEM\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 1.02,\n      \"description\": [\n        \"Synthetic finished item\",\n        \"\",\n        \"Third position\"\n      ]\n    }\n  ],\n  \"consumptionMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_CONSUMPTION_CENTRE\"\n  },\n  \"consumptionLines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_CONSUMPTION_ITEM\"\n      },\n      \"quantity\": 2,\n      \"rate\": 0.5\n    }\n  ],\n  \"narration\": \"Synthetic stock journal\",\n  \"queue\": false,\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"journalReference\": \"{{stockJournalReference}}\",\n  \"date\": \"2026-10-20\",\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"productionMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_PRODUCTION_CENTRE\"\n  },\n  \"productionLines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_PRODUCTION_ITEM\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 1.02,\n      \"description\": [\n        \"Synthetic finished item\",\n        \"\",\n        \"Third position\"\n      ]\n    }\n  ],\n  \"consumptionMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_CONSUMPTION_CENTRE\"\n  },\n  \"consumptionLines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_CONSUMPTION_ITEM\"\n      },\n      \"quantity\": 2,\n      \"rate\": 0.5\n    }\n  ],\n  \"narration\": \"Synthetic stock journal\",\n  \"queue\": false,\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","stock-journal-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"5519ff3a-71d8-394d-4d70-38bf674714bc","name":"SYNTHETIC — 200 mixed; native + stored-row proof","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP0001\",\n  \"financialYear\": \"2026\",\n  \"journalReference\": \"AZSJ-SYNTHETIC-001\",\n  \"date\": \"2026-10-20\",\n  \"voucherSeries\": {\n    \"name\": \"Synthetic Auto Series\"\n  },\n  \"productionMaterialCenter\": {\n    \"name\": \"Synthetic Production Centre\"\n  },\n  \"productionLines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic Finished Item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 1.02,\n      \"description\": [\n        \"Finished item\",\n        \"\",\n        \"Third position\"\n      ]\n    }\n  ],\n  \"consumptionMaterialCenter\": {\n    \"name\": \"Synthetic Consumption Centre\"\n  },\n  \"consumptionLines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic Raw Item\"\n      },\n      \"quantity\": 2,\n      \"rate\": 0.5\n    }\n  ],\n  \"narration\": \"Synthetic stock journal\",\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/stock-journal-create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"journalId\": 9001,\n    \"journalNumber\": \"SJ1\",\n    \"journalReference\": \"AZSJ-SYNTHETIC-001\",\n    \"date\": \"2026-10-20\",\n    \"voucherSeries\": {\n      \"code\": 7100,\n      \"name\": \"Synthetic Auto Series\"\n    },\n    \"baseCurrency\": \"INR\",\n    \"productionMaterialCenter\": {\n      \"code\": 7200,\n      \"name\": \"Synthetic Production Centre\"\n    },\n    \"consumptionMaterialCenter\": {\n      \"code\": 7201,\n      \"name\": \"Synthetic Consumption Centre\"\n    },\n    \"productionLines\": [\n      {\n        \"lineNumber\": 1,\n        \"item\": {\n          \"code\": 7400,\n          \"name\": \"Synthetic Finished Item\"\n        },\n        \"unit\": {\n          \"code\": 7500,\n          \"name\": \"PCS\"\n        },\n        \"alternateUnit\": {\n          \"code\": 7500,\n          \"name\": \"PCS\"\n        },\n        \"conversionFactor\": 1,\n        \"quantity\": 1.25,\n        \"alternateQuantity\": 1.25,\n        \"rate\": 1.02,\n        \"listPrice\": 1.02,\n        \"amount\": 1.28,\n        \"description\": [\n          \"Finished item\",\n          \"\",\n          \"Third position\"\n        ]\n      }\n    ],\n    \"consumptionLines\": [\n      {\n        \"lineNumber\": 1,\n        \"item\": {\n          \"code\": 7401,\n          \"name\": \"Synthetic Raw Item\"\n        },\n        \"unit\": {\n          \"code\": 7500,\n          \"name\": \"PCS\"\n        },\n        \"alternateUnit\": {\n          \"code\": 7500,\n          \"name\": \"PCS\"\n        },\n        \"conversionFactor\": 1,\n        \"quantity\": 2,\n        \"alternateQuantity\": 2,\n        \"rate\": 0.5,\n        \"listPrice\": 0.5,\n        \"amount\": 1,\n        \"description\": []\n      }\n    ],\n    \"productionValue\": 1.28,\n    \"consumptionValue\": 1,\n    \"netStockValue\": 0.28,\n    \"narration\": \"Synthetic stock journal\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.stock-journals.create\",\n    \"requestId\": \"synthetic-stock-journal-001\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 2,\n    \"verification\": [\n      \"busyReadBack\",\n      \"savedRows\"\n    ],\n    \"elapsedMs\": 80,\n    \"executedAt\": \"2026-10-23T10:00:00+00:00\"\n  }\n}"},{"id":"10896b0b-b401-92c1-bea7-6d63ebc6db5a","name":"SYNTHETIC — 200 production only","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP0001\",\n  \"financialYear\": \"2026\",\n  \"journalReference\": \"AZSJ-SYNTHETIC-PROD\",\n  \"date\": \"2026-10-20\",\n  \"voucherSeries\": {\n    \"name\": \"Synthetic Auto Series\"\n  },\n  \"productionMaterialCenter\": {\n    \"name\": \"Synthetic Production Centre\"\n  },\n  \"productionLines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic Finished Item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 1.02\n    }\n  ],\n  \"narration\": \"Synthetic stock journal\",\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/stock-journal-create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"journalId\": 9002,\n    \"journalNumber\": \"SJ2\",\n    \"journalReference\": \"AZSJ-SYNTHETIC-PROD\",\n    \"date\": \"2026-10-20\",\n    \"voucherSeries\": {\n      \"code\": 7100,\n      \"name\": \"Synthetic Auto Series\"\n    },\n    \"baseCurrency\": \"INR\",\n    \"productionMaterialCenter\": {\n      \"code\": 7200,\n      \"name\": \"Synthetic Production Centre\"\n    },\n    \"consumptionMaterialCenter\": null,\n    \"productionLines\": [\n      {\n        \"lineNumber\": 1,\n        \"item\": {\n          \"code\": 7400,\n          \"name\": \"Synthetic Finished Item\"\n        },\n        \"unit\": {\n          \"code\": 7500,\n          \"name\": \"PCS\"\n        },\n        \"alternateUnit\": {\n          \"code\": 7500,\n          \"name\": \"PCS\"\n        },\n        \"conversionFactor\": 1,\n        \"quantity\": 1.25,\n        \"alternateQuantity\": 1.25,\n        \"rate\": 1.02,\n        \"listPrice\": 1.02,\n        \"amount\": 1.28,\n        \"description\": []\n      }\n    ],\n    \"consumptionLines\": [],\n    \"productionValue\": 1.28,\n    \"consumptionValue\": 0,\n    \"netStockValue\": 1.28,\n    \"narration\": \"Synthetic stock journal\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.stock-journals.create\",\n    \"requestId\": \"synthetic-stock-journal-001\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 1,\n    \"verification\": [\n      \"busyReadBack\",\n      \"savedRows\"\n    ],\n    \"elapsedMs\": 80,\n    \"executedAt\": \"2026-10-23T10:00:00+00:00\"\n  }\n}"},{"id":"c597b016-75c8-f248-32c3-9808f3d85f9c","name":"SYNTHETIC — 200 consumption only","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP0001\",\n  \"financialYear\": \"2026\",\n  \"journalReference\": \"AZSJ-SYNTHETIC-CONS\",\n  \"date\": \"2026-10-20\",\n  \"voucherSeries\": {\n    \"name\": \"Synthetic Auto Series\"\n  },\n  \"consumptionMaterialCenter\": {\n    \"name\": \"Synthetic Consumption Centre\"\n  },\n  \"consumptionLines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic Raw Item\"\n      },\n      \"quantity\": 2,\n      \"rate\": 0.5\n    }\n  ],\n  \"narration\": \"Synthetic stock journal\",\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/stock-journal-create"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"journalId\": 9003,\n    \"journalNumber\": \"SJ3\",\n    \"journalReference\": \"AZSJ-SYNTHETIC-CONS\",\n    \"date\": \"2026-10-20\",\n    \"voucherSeries\": {\n      \"code\": 7100,\n      \"name\": \"Synthetic Auto Series\"\n    },\n    \"baseCurrency\": \"INR\",\n    \"productionMaterialCenter\": null,\n    \"consumptionMaterialCenter\": {\n      \"code\": 7201,\n      \"name\": \"Synthetic Consumption Centre\"\n    },\n    \"productionLines\": [],\n    \"consumptionLines\": [\n      {\n        \"lineNumber\": 1,\n        \"item\": {\n          \"code\": 7401,\n          \"name\": \"Synthetic Raw Item\"\n        },\n        \"unit\": {\n          \"code\": 7500,\n          \"name\": \"PCS\"\n        },\n        \"alternateUnit\": {\n          \"code\": 7500,\n          \"name\": \"PCS\"\n        },\n        \"conversionFactor\": 1,\n        \"quantity\": 2,\n        \"alternateQuantity\": 2,\n        \"rate\": 0.5,\n        \"listPrice\": 0.5,\n        \"amount\": 1,\n        \"description\": []\n      }\n    ],\n    \"productionValue\": 0,\n    \"consumptionValue\": 1,\n    \"netStockValue\": -1,\n    \"narration\": \"Synthetic stock journal\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.stock-journals.create\",\n    \"requestId\": \"synthetic-stock-journal-001\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 1,\n    \"verification\": [\n      \"busyReadBack\",\n      \"savedRows\"\n    ],\n    \"elapsedMs\": 80,\n    \"executedAt\": \"2026-10-23T10:00:00+00:00\"\n  }\n}"},{"id":"c9c35064-bf4b-7547-badf-de24b19c4029","name":"SYNTHETIC — 202 queued; not yet saved","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP0001\",\n  \"financialYear\": \"2026\",\n  \"journalReference\": \"AZSJ-SYNTHETIC-001\",\n  \"date\": \"2026-10-20\",\n  \"voucherSeries\": {\n    \"name\": \"Synthetic Auto Series\"\n  },\n  \"productionMaterialCenter\": {\n    \"name\": \"Synthetic Production Centre\"\n  },\n  \"productionLines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic Finished Item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 1.02,\n      \"description\": [\n        \"Finished item\",\n        \"\",\n        \"Third position\"\n      ]\n    }\n  ],\n  \"consumptionMaterialCenter\": {\n    \"name\": \"Synthetic Consumption Centre\"\n  },\n  \"consumptionLines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic Raw Item\"\n      },\n      \"quantity\": 2,\n      \"rate\": 0.5\n    }\n  ],\n  \"narration\": \"Synthetic stock journal\",\n  \"queue\": true\n}"},"url":"{{baseUrl}}/api/v1/stock-journal-create"},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.stock-journals.create\",\n    \"requestId\": \"synthetic-stock-journal-001\",\n    \"jobId\": \"11111111111111111111111111111111\",\n    \"queued\": true,\n    \"status\": \"queued\"\n  }\n}"},{"id":"bae71c7a-4834-c43f-499d-4f4120641d64","name":"SYNTHETIC — 400 INVALID_PARAMETER; bad quantity","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP0001\",\n  \"financialYear\": \"2026\",\n  \"journalReference\": \"AZSJ-SYNTHETIC-001\",\n  \"date\": \"2026-10-20\",\n  \"voucherSeries\": {\n    \"name\": \"Synthetic Auto Series\"\n  },\n  \"productionMaterialCenter\": {\n    \"name\": \"Synthetic Production Centre\"\n  },\n  \"productionLines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic Finished Item\"\n      },\n      \"quantity\": 0,\n      \"rate\": 1.02\n    }\n  ],\n  \"consumptionMaterialCenter\": {\n    \"name\": \"Synthetic Consumption Centre\"\n  },\n  \"consumptionLines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic Raw Item\"\n      },\n      \"quantity\": 2,\n      \"rate\": 0.5\n    }\n  ],\n  \"narration\": \"Synthetic stock journal\",\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/stock-journal-create"},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"Quantity must be positive.\",\n      \"field\": \"productionLines[0].quantity\"\n    },\n    \"requestId\": \"synthetic-stock-journal-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"f739fa64-67e3-bda8-a06f-29661d161e98","name":"SYNTHETIC — 409 STOCK_JOURNAL_REFERENCE_TAKEN","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP0001\",\n  \"financialYear\": \"2026\",\n  \"journalReference\": \"AZSJ-SYNTHETIC-001\",\n  \"date\": \"2026-10-20\",\n  \"voucherSeries\": {\n    \"name\": \"Synthetic Auto Series\"\n  },\n  \"productionMaterialCenter\": {\n    \"name\": \"Synthetic Production Centre\"\n  },\n  \"productionLines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic Finished Item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 1.02,\n      \"description\": [\n        \"Finished item\",\n        \"\",\n        \"Third position\"\n      ]\n    }\n  ],\n  \"consumptionMaterialCenter\": {\n    \"name\": \"Synthetic Consumption Centre\"\n  },\n  \"consumptionLines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic Raw Item\"\n      },\n      \"quantity\": 2,\n      \"rate\": 0.5\n    }\n  ],\n  \"narration\": \"Synthetic stock journal\",\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/stock-journal-create"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"STOCK_JOURNAL_REFERENCE_TAKEN\",\n      \"message\": \"This journalReference is already assigned.\",\n      \"details\": {\n        \"journalId\": 9001\n      }\n    },\n    \"requestId\": \"synthetic-stock-journal-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"71583425-6980-0612-7851-3d2a2c0fff2c","name":"SYNTHETIC — 502 BUSY_WRITE_UNVERIFIED; reconcile saved ID","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP0001\",\n  \"financialYear\": \"2026\",\n  \"journalReference\": \"AZSJ-SYNTHETIC-001\",\n  \"date\": \"2026-10-20\",\n  \"voucherSeries\": {\n    \"name\": \"Synthetic Auto Series\"\n  },\n  \"productionMaterialCenter\": {\n    \"name\": \"Synthetic Production Centre\"\n  },\n  \"productionLines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic Finished Item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 1.02,\n      \"description\": [\n        \"Finished item\",\n        \"\",\n        \"Third position\"\n      ]\n    }\n  ],\n  \"consumptionMaterialCenter\": {\n    \"name\": \"Synthetic Consumption Centre\"\n  },\n  \"consumptionLines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic Raw Item\"\n      },\n      \"quantity\": 2,\n      \"rate\": 0.5\n    }\n  ],\n  \"narration\": \"Synthetic stock journal\",\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/stock-journal-create"},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNVERIFIED\",\n      \"message\": \"BUSY saved the journal but verification differed.\",\n      \"details\": {\n        \"journalId\": 9004,\n        \"mismatchedFields\": [\n          \"productionLines[0].amount\"\n        ]\n      }\n    },\n    \"requestId\": \"synthetic-stock-journal-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"d04a392b-1e5f-8262-84e8-57ddc4f887a9","name":"SYNTHETIC — 504 BUSY_WRITE_UNCERTAIN; do not resend","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP0001\",\n  \"financialYear\": \"2026\",\n  \"journalReference\": \"AZSJ-SYNTHETIC-001\",\n  \"date\": \"2026-10-20\",\n  \"voucherSeries\": {\n    \"name\": \"Synthetic Auto Series\"\n  },\n  \"productionMaterialCenter\": {\n    \"name\": \"Synthetic Production Centre\"\n  },\n  \"productionLines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic Finished Item\"\n      },\n      \"quantity\": 1.25,\n      \"rate\": 1.02,\n      \"description\": [\n        \"Finished item\",\n        \"\",\n        \"Third position\"\n      ]\n    }\n  ],\n  \"consumptionMaterialCenter\": {\n    \"name\": \"Synthetic Consumption Centre\"\n  },\n  \"consumptionLines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic Raw Item\"\n      },\n      \"quantity\": 2,\n      \"rate\": 0.5\n    }\n  ],\n  \"narration\": \"Synthetic stock journal\",\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/stock-journal-create"},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"The journal outcome is uncertain; reconcile before a new attempt.\",\n      \"details\": {\n        \"reconciliation\": \"notChecked\"\n      }\n    },\n    \"requestId\": \"synthetic-stock-journal-001\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"0462e5af-24d0-03c6-89b8-00ebe1841777"},{"name":"⚠ WRITE BUSY — Sales invoice Bill Sundry local CGST+SGST","id":"76672437-b920-0ef8-c533-4295fa26e5b5","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\r\n  \"companyCode\": \"{{busy_company_code}}\",\r\n  \"financialYear\": \"{{busy_financial_year}}\",\r\n  \"invoiceReference\": \"SYN-GST-BS-LOCAL-{{case_nonce}}\",\r\n  \"date\": \"{{voucher_date}}\",\r\n  \"voucherSeries\": {\r\n    \"name\": \"{{sales_series}}\"\r\n  },\r\n  \"customer\": {\r\n    \"code\": {{local_customer_code}}\r\n  },\r\n  \"saleType\": {\r\n    \"name\": \"Local-MultiRate\"\r\n  },\r\n  \"materialCenter\": {\r\n    \"name\": \"{{material_center}}\"\r\n  },\r\n  \"taxLocation\": \"billSundry\",\r\n  \"taxCalculation\": \"auto\",\r\n  \"pricingMode\": \"gstExclusive\",\r\n  \"lines\": [\r\n    {\r\n      \"item\": {\r\n        \"code\": {{gst18_item_code}}\r\n      },\r\n      \"quantity\": 1,\r\n      \"rate\": 100.1\r\n    }\r\n  ],\r\n  \"billSundries\": [\r\n    {\r\n      \"billSundry\": {\r\n        \"name\": \"CGST\"\r\n      }\r\n    },\r\n    {\r\n      \"billSundry\": {\r\n        \"name\": \"SGST\"\r\n      }\r\n    },\r\n    {\r\n      \"billSundry\": {\r\n        \"name\": \"Rounded Off (-)\"\r\n      },\r\n      \"amount\": 0.12\r\n    }\r\n  ]\r\n}"},"url":"{{baseUrl}}/api/v1/sales-invoice-create","description":"<p>WRITE BUSY — explicit voucher-level Bill Sundry GST (local CGST+SGST). Before Send, set busy_company_code=COMP0003 and busy_financial_year=2026 for this development fixture. Set voucher_date, case_nonce, sales_series, material_center and the two numeric master-code variables to current verified synthetic masters in the mapped company; unresolved code variables make the raw JSON invalid. This writes one BUSY invoice and may change financial data. Use a new reference only for a genuinely new intent; never retry an uncertain write with a new reference. HTTP 202 means queued, not saved; verify the job, saved voucher, GST summary and ledger. Cess is unsupported. No collection/request scripts. Expected base 100.10, CGST 9.01, SGST 9.01, subtractive round-off 0.12, total 118.00.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","sales-invoice-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"76672437-b920-0ef8-c533-4295fa26e5b5"},{"name":"⚠ WRITE BUSY — Sales invoice Bill Sundry central IGST","id":"34e8a33a-4cca-c3f9-e8b1-9377ce415acc","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\r\n  \"companyCode\": \"{{busy_company_code}}\",\r\n  \"financialYear\": \"{{busy_financial_year}}\",\r\n  \"invoiceReference\": \"SYN-GST-BS-CENTRAL-{{case_nonce}}\",\r\n  \"date\": \"{{voucher_date}}\",\r\n  \"voucherSeries\": {\r\n    \"name\": \"{{sales_series}}\"\r\n  },\r\n  \"customer\": {\r\n    \"code\": {{interstate_customer_code}}\r\n  },\r\n  \"saleType\": {\r\n    \"name\": \"Central-MultiRate\"\r\n  },\r\n  \"materialCenter\": {\r\n    \"name\": \"{{material_center}}\"\r\n  },\r\n  \"taxLocation\": \"billSundry\",\r\n  \"taxCalculation\": \"auto\",\r\n  \"pricingMode\": \"gstExclusive\",\r\n  \"lines\": [\r\n    {\r\n      \"item\": {\r\n        \"code\": {{gst18_item_code}}\r\n      },\r\n      \"quantity\": 1,\r\n      \"rate\": 100.1\r\n    }\r\n  ],\r\n  \"billSundries\": [\r\n    {\r\n      \"billSundry\": {\r\n        \"name\": \"IGST\"\r\n      }\r\n    },\r\n    {\r\n      \"billSundry\": {\r\n        \"name\": \"Rounded Off (-)\"\r\n      },\r\n      \"amount\": 0.12\r\n    }\r\n  ]\r\n}"},"url":"{{baseUrl}}/api/v1/sales-invoice-create","description":"<p>WRITE BUSY — explicit voucher-level Bill Sundry GST (central IGST). Before Send, set busy_company_code=COMP0003 and busy_financial_year=2026 for this development fixture. Set voucher_date, case_nonce, sales_series, material_center and the two numeric master-code variables to current verified synthetic masters in the mapped company; unresolved code variables make the raw JSON invalid. This writes one BUSY invoice and may change financial data. Use a new reference only for a genuinely new intent; never retry an uncertain write with a new reference. HTTP 202 means queued, not saved; verify the job, saved voucher, GST summary and ledger. Cess is unsupported. No collection/request scripts. Expected base 100.10, IGST 18.02, subtractive round-off 0.12, total 118.00.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","sales-invoice-create"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"34e8a33a-4cca-c3f9-e8b1-9377ce415acc"}],"id":"1c4adda0-7768-4608-88dc-a92dd0029d4c","description":"<p><strong>Writes to the BUSY books.</strong> Create vouchers through BUSY's own COM component — <strong>sales orders, sales invoices, receipts, sales returns (credit notes), purchases, purchase returns (debit notes) and payments</strong>. AI Zeny calculates GST where needed, and every voucher is read back (and, for receipts, sales returns, purchase returns and payments, the settled bills re-read) before a success. A payment is an accounting entry only: nothing is paid or transferred. In the AI Zeny Development environment, Local voucher creates send without an extra confirmation. Each Send generates a fresh synthetic reference when <code>autoVoucherReferences=yes</code>; set it to <code>no</code> to enter one yourself. The request body uses the selected <code>companyCode</code>. Receipts, sales returns, purchases, purchase returns and payments share one settlement lock on the PC. <strong>Local only: the AI Zeny cloud has no route for these creates yet</strong> (the receipt and sales-return routes will be added together; purchases, purchase returns and payments have no cloud route planned). Voucher PDFs are separate; printing an existing voucher can change BUSY's print flag.</p>\n","_postman_id":"1c4adda0-7768-4608-88dc-a92dd0029d4c","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ PC Settings & Management — changes AI Zeny, not BUSY","item":[{"name":"⚠ Check for updates now","id":"904d4f79-4683-f705-639c-7fe6fbb032a1","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/updates/check","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/updates/check</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Asks the <strong>AI Zeny Updater</strong> Windows service (D41) to check the signed stable channel now (the Host sends it SCM control 128). Answers at once; the service ignores requests within a minute of the last one. There is no endpoint that confirms or activates an update.</p>\n<p><strong>Effect:</strong> if a newer verified version is published, it downloads and <strong>installs automatically</strong>: AI Zeny closes, the Host restarts on the new version (Local API requests get <code>503 HOST_STOPPING</code> for about a minute), and AI Zeny reopens locked. Watch <code>/status</code> → <code>data.updates.phase</code> (<code>downloading</code> → <code>applying</code> → <code>upToDate</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td><code>{ \"success\": true, \"data\": { \"accepted\": true, \"version\": null, \"code\": null }, \"metadata\": {} }</code> — the service was signalled</td>\n</tr>\n<tr>\n<td>200</td>\n<td><code>{ \"success\": true, \"data\": { \"accepted\": false, \"version\": null, \"code\": \"UPDATER_SERVICE_STOPPED\" }, \"metadata\": {} }</code> — the updater service is not running</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>NOT_FOUND</code> — this Host has no updater</td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","updates","check"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"b72a06e2-07c0-6fa4-6176-b8d6e90a5ae2","name":"200 OK – updater signalled","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/updates/check","description":"**Local** · `POST {{baseUrl}}/api/v1/updates/check` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually.** Asks the **AI Zeny Updater** Windows service (D41) to check the signed stable channel now (the Host sends it SCM control 128). Answers at once; the service ignores requests within a minute of the last one. There is no endpoint that confirms or activates an update.\n\n**Effect:** if a newer verified version is published, it downloads and **installs automatically**: AI Zeny closes, the Host restarts on the new version (Local API requests get `503 HOST_STOPPING` for about a minute), and AI Zeny reopens locked. Watch `/status` → `data.updates.phase` (`downloading` → `applying` → `upToDate`).\n\n| Status | Body |\n|---|---|\n| 200 | `{ \"success\": true, \"data\": { \"accepted\": true, \"version\": null, \"code\": null }, \"metadata\": {} }` — the service was signalled |\n| 200 | `{ \"success\": true, \"data\": { \"accepted\": false, \"version\": null, \"code\": \"UPDATER_SERVICE_STOPPED\" }, \"metadata\": {} }` — the updater service is not running |\n| 404 | `NOT_FOUND` — this Host has no updater |\n\nGuard: skipped unless `confirmMutating` = `yes`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"b1c2d3e4f5a6478899aabbccddeeff00","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"accepted\":true,\"version\":null,\"code\":null},\"metadata\":{}}"},{"id":"e5f7c58e-93da-8826-099f-e56f21d47b4e","name":"200 OK – updater service not running","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/updates/check","description":"**Local** · `POST {{baseUrl}}/api/v1/updates/check` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually.** Asks the **AI Zeny Updater** Windows service (D41) to check the signed stable channel now (the Host sends it SCM control 128). Answers at once; the service ignores requests within a minute of the last one. There is no endpoint that confirms or activates an update.\n\n**Effect:** if a newer verified version is published, it downloads and **installs automatically**: AI Zeny closes, the Host restarts on the new version (Local API requests get `503 HOST_STOPPING` for about a minute), and AI Zeny reopens locked. Watch `/status` → `data.updates.phase` (`downloading` → `applying` → `upToDate`).\n\n| Status | Body |\n|---|---|\n| 200 | `{ \"success\": true, \"data\": { \"accepted\": true, \"version\": null, \"code\": null }, \"metadata\": {} }` — the service was signalled |\n| 200 | `{ \"success\": true, \"data\": { \"accepted\": false, \"version\": null, \"code\": \"UPDATER_SERVICE_STOPPED\" }, \"metadata\": {} }` — the updater service is not running |\n| 404 | `NOT_FOUND` — this Host has no updater |\n\nGuard: skipped unless `confirmMutating` = `yes`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"c2d3e4f5a6b7489900aabbccddeeff11","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"accepted\":false,\"version\":null,\"code\":\"UPDATER_SERVICE_STOPPED\"},\"metadata\":{}}"}],"_postman_id":"904d4f79-4683-f705-639c-7fe6fbb032a1"},{"name":"⚠ Restart a component (pusher)","id":"b060f5df-a0c5-796a-788f-eee1114d152d","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/services/pusher/restart","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/services/pusher/restart</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Restarts one supervised component inside the AI Zeny Host. The route is <code>/api/v1/services/{name}/restart</code>; <code>{name}</code> is <code>pusher</code> or <code>updater</code> (edit the URL for the updater). <code>health-check</code> and <code>local-api</code> can never be restarted through the API, and the Host itself is never restarted.</p>\n<p><strong>Effect:</strong> the Pusher disconnects and reconnects to its private channel (a few seconds without relay delivery); the Updater component only watches the updater service, so restarting it is harmless.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body / code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td><code>data</code>: <code>{ \"service\": \"AI Zeny Pusher\", \"slug\": \"pusher\", \"outcome\": \"restarted\" }</code></td>\n</tr>\n<tr>\n<td>403</td>\n<td><code>SERVICE_RESTART_NOT_ALLOWED</code> (health-check, local-api)</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>SERVICE_NOT_FOUND</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","services","pusher","restart"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"3a266b15-c7dd-39d5-1482-73dac555c43c","name":"200 OK – restarted","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/services/pusher/restart","description":"**Local** · `POST {{baseUrl}}/api/v1/services/pusher/restart` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually.** Restarts one supervised component inside the AI Zeny Host. The route is `/api/v1/services/{name}/restart`; `{name}` is `pusher` or `updater` (edit the URL for the updater). `health-check` and `local-api` can never be restarted through the API, and the Host itself is never restarted.\n\n**Effect:** the Pusher disconnects and reconnects to its private channel (a few seconds without relay delivery); the Updater component only watches the updater service, so restarting it is harmless.\n\n| Status | Body / code |\n|---|---|\n| 200 | `data`: `{ \"service\": \"AI Zeny Pusher\", \"slug\": \"pusher\", \"outcome\": \"restarted\" }` |\n| 403 | `SERVICE_RESTART_NOT_ALLOWED` (health-check, local-api) |\n| 404 | `SERVICE_NOT_FOUND` |\n\nGuard: skipped unless `confirmMutating` = `yes`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"d3e4f5a6b7c8490011aabbccddeeff22"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"service\":\"AI Zeny Pusher\",\"slug\":\"pusher\",\"outcome\":\"restarted\"},\"metadata\":{}}"},{"id":"db37a42f-9f69-aa7a-8ed6-203bf42c51d0","name":"403 SERVICE_RESTART_NOT_ALLOWED (local-api)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/services/pusher/restart","description":"**Local** · `POST {{baseUrl}}/api/v1/services/pusher/restart` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually.** Restarts one supervised component inside the AI Zeny Host. The route is `/api/v1/services/{name}/restart`; `{name}` is `pusher` or `updater` (edit the URL for the updater). `health-check` and `local-api` can never be restarted through the API, and the Host itself is never restarted.\n\n**Effect:** the Pusher disconnects and reconnects to its private channel (a few seconds without relay delivery); the Updater component only watches the updater service, so restarting it is harmless.\n\n| Status | Body / code |\n|---|---|\n| 200 | `data`: `{ \"service\": \"AI Zeny Pusher\", \"slug\": \"pusher\", \"outcome\": \"restarted\" }` |\n| 403 | `SERVICE_RESTART_NOT_ALLOWED` (health-check, local-api) |\n| 404 | `SERVICE_NOT_FOUND` |\n\nGuard: skipped unless `confirmMutating` = `yes`."},"status":"Forbidden","code":403,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"e4f5a6b7c8d9401122aabbccddeeff33","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"SERVICE_RESTART_NOT_ALLOWED\",\"message\":\"That component cannot be restarted through the API.\"},\"requestId\":\"e4f5a6b7c8d9401122aabbccddeeff33\"}}"}],"_postman_id":"b060f5df-a0c5-796a-788f-eee1114d152d"},{"name":"⚠ Regenerate the Bearer token (breaks all clients)","id":"e4578633-dd34-dab6-3b87-7c18304abe14","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/token/regenerate","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/token/regenerate</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually. Breaks every Local API client</strong> (other apps, scripts, this Postman environment) until they are given the new token.</p>\n<p>The Host writes a new 32-byte token to the protected <code>%ProgramData%\\AI Zeny\\local-api.token</code> first; from the next request on, the old token is refused with <code>401</code>. The response <strong>never</strong> contains the new token: copy it again from AI Zeny (<em>BUSY Data → Local API → Reveal / Copy token</em>, GUI unlocked) and paste it into <code>localApiToken</code> (current value only). The AI Zeny window re-reads the file by itself. Same as the page's <strong>Regenerate token</strong> button.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td><code>{ \"success\": true, \"data\": { \"regenerated\": true }, \"metadata\": {} }</code></td>\n</tr>\n<tr>\n<td>500</td>\n<td><code>INTERNAL_ERROR</code> — the file could not be written; the current token still works</td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","token","regenerate"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"6afea14c-e9d1-f875-f052-ce83e8b86f76","name":"200 OK – token regenerated (never returned)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/token/regenerate","description":"**Local** · `POST {{baseUrl}}/api/v1/token/regenerate` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually. Breaks every Local API client** (other apps, scripts, this Postman environment) until they are given the new token.\n\nThe Host writes a new 32-byte token to the protected `%ProgramData%\\AI Zeny\\local-api.token` first; from the next request on, the old token is refused with `401`. The response **never** contains the new token: copy it again from AI Zeny (*BUSY Data → Local API → Reveal / Copy token*, GUI unlocked) and paste it into `localApiToken` (current value only). The AI Zeny window re-reads the file by itself. Same as the page's **Regenerate token** button.\n\n| Status | Body |\n|---|---|\n| 200 | `{ \"success\": true, \"data\": { \"regenerated\": true }, \"metadata\": {} }` |\n| 500 | `INTERNAL_ERROR` — the file could not be written; the current token still works |\n\nGuard: skipped unless `confirmMutating` = `yes`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"f5a6b7c8d9e0411233aabbccddeeff44","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"regenerated\":true},\"metadata\":{}}"}],"_postman_id":"e4578633-dd34-dab6-3b87-7c18304abe14"},{"name":"⚠ BUSY company – create (SQL Server)","id":"3140b363-f4e9-cd63-6a95-100cf494aff1","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"displayName\": \"Example Traders\",\n  \"provider\": \"sqlServer\",\n  \"sqlServer\": {\n    \"server\": \"BUSYSERVER\\\\SQLEXPRESS\",\n    \"port\": null,\n    \"authentication\": \"sqlLogin\",\n    \"userName\": \"busyreader\",\n    \"password\": \"{{busySqlPassword}}\",\n    \"encrypt\": true,\n    \"trustServerCertificate\": true\n  },\n  \"access\": null,\n  \"enabled\": true,\n  \"allowedFinancialYears\": [\"2026\"]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/companies","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/companies</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Adds a BUSY company on <strong>SQL Server</strong> to AI Zeny on this PC.</p>\n<ul>\n<li><code>companyCode</code>: BUSY's company code, <code>^[A-Z0-9_-]{1,32}$</code> (the only company code, D38). Taken from <code>{{targetCompanyCode}}</code>.</li>\n<li><code>sqlServer.server</code>: <code>host</code> or <code>host\\instance</code>; <code>port</code> optional (null = default / SQL Browser).</li>\n<li><code>authentication</code>: <code>windows</code> (the Host's service account signs in; omit userName/password) or <code>sqlLogin</code>.</li>\n<li><code>password</code>: write-only. Put it in <code>busySqlPassword</code> as a <strong>current value only</strong> — never type it into the saved body. It is sealed on the PC and never returned (<code>hasPassword</code> only).</li>\n<li><code>allowedFinancialYears</code>: four-digit starting years (<code>\"2026\"</code>), 1 – 40, within the plan's per-company year limit.</li>\n<li>Unknown members are refused (<code>BAD_REQUEST</code>); exactly one of <code>sqlServer</code> / <code>access</code>.</li>\n</ul>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body / code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the saved company (same shape as in <em>List BUSY companies</em>)</td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>BAD_REQUEST</code>, <code>BUSY_COMPANY_INVALID</code> (message names the problem)</td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>BUSY_COMPANY_DUPLICATE</code>, <code>BUSY_COMPANY_LIMIT</code>, <code>BUSY_PLAN_UNKNOWN</code></td>\n</tr>\n<tr>\n<td>503</td>\n<td><code>BUSY_SECRET_STORE_LOCKED</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","companies"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"5521c9bf-ec4f-c1d1-1ed7-7d1572e0d3d1","name":"200 OK – saved (password never returned)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"displayName\": \"Example Traders\",\n  \"provider\": \"sqlServer\",\n  \"sqlServer\": {\n    \"server\": \"BUSYSERVER\\\\SQLEXPRESS\",\n    \"port\": null,\n    \"authentication\": \"sqlLogin\",\n    \"userName\": \"busyreader\",\n    \"password\": \"{{busySqlPassword}}\",\n    \"encrypt\": true,\n    \"trustServerCertificate\": true\n  },\n  \"access\": null,\n  \"enabled\": true,\n  \"allowedFinancialYears\": [\"2026\"]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/companies","description":"**Local** · `POST {{baseUrl}}/api/v1/busy/companies` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually.** Adds a BUSY company on **SQL Server** to AI Zeny on this PC.\n\n- `companyCode`: BUSY's company code, `^[A-Z0-9_-]{1,32}$` (the only company code, D38). Taken from `{{targetCompanyCode}}`.\n- `sqlServer.server`: `host` or `host\\instance`; `port` optional (null = default / SQL Browser).\n- `authentication`: `windows` (the Host's service account signs in; omit userName/password) or `sqlLogin`.\n- `password`: write-only. Put it in `busySqlPassword` as a **current value only** — never type it into the saved body. It is sealed on the PC and never returned (`hasPassword` only).\n- `allowedFinancialYears`: four-digit starting years (`\"2026\"`), 1 – 40, within the plan's per-company year limit.\n- Unknown members are refused (`BAD_REQUEST`); exactly one of `sqlServer` / `access`.\n\n| Status | Body / code |\n|---|---|\n| 200 | the saved company (same shape as in *List BUSY companies*) |\n| 400 | `BAD_REQUEST`, `BUSY_COMPANY_INVALID` (message names the problem) |\n| 409 | `BUSY_COMPANY_DUPLICATE`, `BUSY_COMPANY_LIMIT`, `BUSY_PLAN_UNKNOWN` |\n| 503 | `BUSY_SECRET_STORE_LOCKED` |\n\nGuard: skipped unless `confirmMutating` = `yes`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"a6b7c8d9e0f1421344aabbccddeeff55"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"companyCode\": \"COMP0099\",\n    \"displayName\": \"Example Traders\",\n    \"provider\": \"sqlServer\",\n    \"sqlServer\": { \"server\": \"BUSYSERVER\\\\SQLEXPRESS\", \"port\": null, \"authentication\": \"sqlLogin\", \"userName\": \"busyreader\", \"hasPassword\": true, \"encrypt\": true, \"trustServerCertificate\": true },\n    \"access\": null,\n    \"enabled\": true,\n    \"lastValidatedUtc\": null,\n    \"lastValidationCode\": null,\n    \"allowedFinancialYears\": [\"2026\"],\n    \"foundFinancialYears\": [],\n    \"updatedUtc\": \"2026-09-26T05:45:00.0000000+00:00\"\n  },\n  \"metadata\": {}\n}"},{"id":"f948098b-348e-889b-29b0-8a888efc17de","name":"409 BUSY_COMPANY_LIMIT","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"displayName\": \"Example Traders\",\n  \"provider\": \"sqlServer\",\n  \"sqlServer\": {\n    \"server\": \"BUSYSERVER\\\\SQLEXPRESS\",\n    \"port\": null,\n    \"authentication\": \"sqlLogin\",\n    \"userName\": \"busyreader\",\n    \"password\": \"{{busySqlPassword}}\",\n    \"encrypt\": true,\n    \"trustServerCertificate\": true\n  },\n  \"access\": null,\n  \"enabled\": true,\n  \"allowedFinancialYears\": [\"2026\"]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/companies","description":"**Local** · `POST {{baseUrl}}/api/v1/busy/companies` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually.** Adds a BUSY company on **SQL Server** to AI Zeny on this PC.\n\n- `companyCode`: BUSY's company code, `^[A-Z0-9_-]{1,32}$` (the only company code, D38). Taken from `{{targetCompanyCode}}`.\n- `sqlServer.server`: `host` or `host\\instance`; `port` optional (null = default / SQL Browser).\n- `authentication`: `windows` (the Host's service account signs in; omit userName/password) or `sqlLogin`.\n- `password`: write-only. Put it in `busySqlPassword` as a **current value only** — never type it into the saved body. It is sealed on the PC and never returned (`hasPassword` only).\n- `allowedFinancialYears`: four-digit starting years (`\"2026\"`), 1 – 40, within the plan's per-company year limit.\n- Unknown members are refused (`BAD_REQUEST`); exactly one of `sqlServer` / `access`.\n\n| Status | Body / code |\n|---|---|\n| 200 | the saved company (same shape as in *List BUSY companies*) |\n| 400 | `BAD_REQUEST`, `BUSY_COMPANY_INVALID` (message names the problem) |\n| 409 | `BUSY_COMPANY_DUPLICATE`, `BUSY_COMPANY_LIMIT`, `BUSY_PLAN_UNKNOWN` |\n| 503 | `BUSY_SECRET_STORE_LOCKED` |\n\nGuard: skipped unless `confirmMutating` = `yes`."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"b7c8d9e0f1a2431455aabbccddeeff66","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"BUSY_COMPANY_LIMIT\",\"message\":\"Your plan's company limit is reached. Delete a company to add another.\"},\"requestId\":\"b7c8d9e0f1a2431455aabbccddeeff66\"}}"}],"_postman_id":"3140b363-f4e9-cd63-6a95-100cf494aff1"},{"name":"⚠ BUSY company – create (Access)","id":"b48db45e-3de2-02a8-7234-1d97a7e42164","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"displayName\": \"Example Stores\",\n  \"provider\": \"access\",\n  \"sqlServer\": null,\n  \"access\": {\n    \"dataFolder\": \"C:\\\\BusyWin\\\\DATA\"\n  },\n  \"enabled\": true,\n  \"allowedFinancialYears\": [\"2026\"]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/companies","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/companies</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Adds a BUSY company on <strong>Microsoft Access</strong> (<code>.bds</code> files) to AI Zeny on this PC.</p>\n<ul>\n<li><code>access.dataFolder</code>: the BUSY data folder that holds <code>{companyCode}\\db.bds</code> and the year files.</li>\n<li>There is <strong>no password</strong> for Access: AI Zeny opens BUSY's files with BUSY's built-in password internally (D35). Sending any password or SQL sign-in member for Access is refused.</li>\n<li><code>allowedFinancialYears</code>: four-digit starting years (<code>\"2026\"</code>).</li>\n</ul>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body / code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the saved company</td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>BAD_REQUEST</code>, <code>BUSY_COMPANY_INVALID</code></td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>BUSY_COMPANY_DUPLICATE</code>, <code>BUSY_COMPANY_LIMIT</code>, <code>BUSY_PLAN_UNKNOWN</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","companies"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"c3d9f111-0276-1e0d-c6b3-9849089de8ee","name":"200 OK – saved","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"displayName\": \"Example Stores\",\n  \"provider\": \"access\",\n  \"sqlServer\": null,\n  \"access\": {\n    \"dataFolder\": \"C:\\\\BusyWin\\\\DATA\"\n  },\n  \"enabled\": true,\n  \"allowedFinancialYears\": [\"2026\"]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/companies","description":"**Local** · `POST {{baseUrl}}/api/v1/busy/companies` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually.** Adds a BUSY company on **Microsoft Access** (`.bds` files) to AI Zeny on this PC.\n\n- `access.dataFolder`: the BUSY data folder that holds `{companyCode}\\db.bds` and the year files.\n- There is **no password** for Access: AI Zeny opens BUSY's files with BUSY's built-in password internally (D35). Sending any password or SQL sign-in member for Access is refused.\n- `allowedFinancialYears`: four-digit starting years (`\"2026\"`).\n\n| Status | Body / code |\n|---|---|\n| 200 | the saved company |\n| 400 | `BAD_REQUEST`, `BUSY_COMPANY_INVALID` |\n| 409 | `BUSY_COMPANY_DUPLICATE`, `BUSY_COMPANY_LIMIT`, `BUSY_PLAN_UNKNOWN` |\n\nGuard: skipped unless `confirmMutating` = `yes`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"c8d9e0f1a2b3441566aabbccddeeff77","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"companyCode\": \"COMP0098\",\n    \"displayName\": \"Example Stores\",\n    \"provider\": \"access\",\n    \"sqlServer\": null,\n    \"access\": { \"dataFolder\": \"C:\\\\BusyWin\\\\DATA\" },\n    \"enabled\": true,\n    \"lastValidatedUtc\": null,\n    \"lastValidationCode\": null,\n    \"allowedFinancialYears\": [\"2026\"],\n    \"foundFinancialYears\": [],\n    \"updatedUtc\": \"2026-09-26T05:46:00.0000000+00:00\"\n  },\n  \"metadata\": {}\n}"},{"id":"e65f1ce4-c65e-8462-9242-2ced885a7cd0","name":"409 BUSY_COMPANY_DUPLICATE","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"displayName\": \"Example Stores\",\n  \"provider\": \"access\",\n  \"sqlServer\": null,\n  \"access\": {\n    \"dataFolder\": \"C:\\\\BusyWin\\\\DATA\"\n  },\n  \"enabled\": true,\n  \"allowedFinancialYears\": [\"2026\"]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/companies","description":"**Local** · `POST {{baseUrl}}/api/v1/busy/companies` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually.** Adds a BUSY company on **Microsoft Access** (`.bds` files) to AI Zeny on this PC.\n\n- `access.dataFolder`: the BUSY data folder that holds `{companyCode}\\db.bds` and the year files.\n- There is **no password** for Access: AI Zeny opens BUSY's files with BUSY's built-in password internally (D35). Sending any password or SQL sign-in member for Access is refused.\n- `allowedFinancialYears`: four-digit starting years (`\"2026\"`).\n\n| Status | Body / code |\n|---|---|\n| 200 | the saved company |\n| 400 | `BAD_REQUEST`, `BUSY_COMPANY_INVALID` |\n| 409 | `BUSY_COMPANY_DUPLICATE`, `BUSY_COMPANY_LIMIT`, `BUSY_PLAN_UNKNOWN` |\n\nGuard: skipped unless `confirmMutating` = `yes`."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"d9e0f1a2b3c4451677aabbccddeeff88"}],"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"BUSY_COMPANY_DUPLICATE\",\"message\":\"Another company on this PC already uses that code.\"},\"requestId\":\"d9e0f1a2b3c4451677aabbccddeeff88\"}}"}],"_postman_id":"b48db45e-3de2-02a8-7234-1d97a7e42164"},{"name":"⚠ BUSY company – update","id":"d667341a-c1be-00d1-d7ca-d1e4db9c2646","request":{"method":"PUT","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"displayName\": \"Example Traders\",\n  \"provider\": \"sqlServer\",\n  \"sqlServer\": {\n    \"server\": \"BUSYSERVER\\\\SQLEXPRESS\",\n    \"port\": null,\n    \"authentication\": \"sqlLogin\",\n    \"userName\": \"busyreader\",\n    \"password\": null,\n    \"encrypt\": true,\n    \"trustServerCertificate\": true\n  },\n  \"access\": null,\n  \"enabled\": true,\n  \"allowedFinancialYears\": [\"2025\", \"2026\"]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}","description":"<p><strong>Local</strong> · <code>PUT {{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Replaces the configuration of the company <code>{{targetCompanyCode}}</code> (URL) with the body (same rules as <em>create</em>). The company code itself never changes.</p>\n<ul>\n<li>SQL Server <code>password</code>: <strong><code>null</code> keeps the stored password</strong> (do not send an empty string); send <code>{{busySqlPassword}}</code> only to change it.</li>\n<li>Changing where or how to connect clears the last test result.</li>\n<li>Removing years is always allowed; adding a company or years needs a known plan (<code>BUSY_PLAN_UNKNOWN</code> otherwise) within its limits.</li>\n</ul>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body / code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the saved company</td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>BAD_REQUEST</code>, <code>BUSY_COMPANY_INVALID</code></td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>BUSY_COMPANY_NOT_FOUND</code></td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>BUSY_COMPANY_DUPLICATE</code>, <code>BUSY_COMPANY_NEEDS_CORRECTION</code>, <code>BUSY_COMPANY_LIMIT</code>, <code>BUSY_PLAN_UNKNOWN</code></td>\n</tr>\n<tr>\n<td>503</td>\n<td><code>BUSY_SECRET_STORE_LOCKED</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","companies","{{targetCompanyCode}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"766faa2d-de25-73ff-7e59-d1835de78759","name":"200 OK – saved (stored password kept)","originalRequest":{"method":"PUT","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"displayName\": \"Example Traders\",\n  \"provider\": \"sqlServer\",\n  \"sqlServer\": {\n    \"server\": \"BUSYSERVER\\\\SQLEXPRESS\",\n    \"port\": null,\n    \"authentication\": \"sqlLogin\",\n    \"userName\": \"busyreader\",\n    \"password\": null,\n    \"encrypt\": true,\n    \"trustServerCertificate\": true\n  },\n  \"access\": null,\n  \"enabled\": true,\n  \"allowedFinancialYears\": [\"2025\", \"2026\"]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}","description":"**Local** · `PUT {{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually.** Replaces the configuration of the company `{{targetCompanyCode}}` (URL) with the body (same rules as *create*). The company code itself never changes.\n\n- SQL Server `password`: **`null` keeps the stored password** (do not send an empty string); send `{{busySqlPassword}}` only to change it.\n- Changing where or how to connect clears the last test result.\n- Removing years is always allowed; adding a company or years needs a known plan (`BUSY_PLAN_UNKNOWN` otherwise) within its limits.\n\n| Status | Body / code |\n|---|---|\n| 200 | the saved company |\n| 400 | `BAD_REQUEST`, `BUSY_COMPANY_INVALID` |\n| 404 | `BUSY_COMPANY_NOT_FOUND` |\n| 409 | `BUSY_COMPANY_DUPLICATE`, `BUSY_COMPANY_NEEDS_CORRECTION`, `BUSY_COMPANY_LIMIT`, `BUSY_PLAN_UNKNOWN` |\n| 503 | `BUSY_SECRET_STORE_LOCKED` |\n\nGuard: skipped unless `confirmMutating` = `yes`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"e0f1a2b3c4d5461788aabbccddeeff99","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"companyCode\": \"COMP0099\",\n    \"displayName\": \"Example Traders\",\n    \"provider\": \"sqlServer\",\n    \"sqlServer\": { \"server\": \"BUSYSERVER\\\\SQLEXPRESS\", \"port\": null, \"authentication\": \"sqlLogin\", \"userName\": \"busyreader\", \"hasPassword\": true, \"encrypt\": true, \"trustServerCertificate\": true },\n    \"access\": null,\n    \"enabled\": true,\n    \"lastValidatedUtc\": \"2026-09-26T05:47:10.0000000+00:00\",\n    \"lastValidationCode\": \"OK\",\n    \"allowedFinancialYears\": [\"2025\", \"2026\"],\n    \"foundFinancialYears\": [\"2025\", \"2026\"],\n    \"updatedUtc\": \"2026-09-26T05:48:00.0000000+00:00\"\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"d667341a-c1be-00d1-d7ca-d1e4db9c2646"},{"name":"⚠ BUSY company – enable","id":"576d97ed-1c53-222c-af74-e3126d1aa29e","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}/enable","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}/enable</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Enables the company <code>{{targetCompanyCode}}</code>: relay commands and V1 data operations may use it again. No body.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body / code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the company with <code>\"enabled\": true</code></td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>BUSY_COMPANY_NOT_FOUND</code></td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>BUSY_COMPANY_NEEDS_CORRECTION</code>, <code>BUSY_COMPANY_LIMIT</code>, <code>BUSY_PLAN_UNKNOWN</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","companies","{{targetCompanyCode}}","enable"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"1d5490b3-364d-c435-13a6-e38900179ded","name":"200 OK – enabled","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}/enable","description":"**Local** · `POST {{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}/enable` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually.** Enables the company `{{targetCompanyCode}}`: relay commands and V1 data operations may use it again. No body.\n\n| Status | Body / code |\n|---|---|\n| 200 | the company with `\"enabled\": true` |\n| 404 | `BUSY_COMPANY_NOT_FOUND` |\n| 409 | `BUSY_COMPANY_NEEDS_CORRECTION`, `BUSY_COMPANY_LIMIT`, `BUSY_PLAN_UNKNOWN` |\n\nGuard: skipped unless `confirmMutating` = `yes`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"f1a2b3c4d5e6471899aabbccddeeffaa"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"companyCode\":\"COMP0098\",\"displayName\":\"Example Stores\",\"provider\":\"access\",\"sqlServer\":null,\"access\":{\"dataFolder\":\"C:\\\\BusyWin\\\\DATA\"},\"enabled\":true,\"lastValidatedUtc\":null,\"lastValidationCode\":null,\"allowedFinancialYears\":[\"2026\"],\"foundFinancialYears\":[],\"updatedUtc\":\"2026-09-26T05:49:00.0000000+00:00\"},\"metadata\":{}}"}],"_postman_id":"576d97ed-1c53-222c-af74-e3126d1aa29e"},{"name":"⚠ BUSY company – disable","id":"984fbbe4-ba83-1de2-af69-b9fda8631565","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}/disable","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}/disable</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Disables the company <code>{{targetCompanyCode}}</code>: relay commands and V1 data operations refuse it (<code>COMPANY_DISABLED</code>) until it is enabled again. Nothing is deleted. No body.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body / code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the company with <code>\"enabled\": false</code></td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>BUSY_COMPANY_NOT_FOUND</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","companies","{{targetCompanyCode}}","disable"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"6b9bd544-89be-47c7-264f-6da29ee734e8","name":"200 OK – disabled","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}/disable","description":"**Local** · `POST {{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}/disable` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually.** Disables the company `{{targetCompanyCode}}`: relay commands and V1 data operations refuse it (`COMPANY_DISABLED`) until it is enabled again. Nothing is deleted. No body.\n\n| Status | Body / code |\n|---|---|\n| 200 | the company with `\"enabled\": false` |\n| 404 | `BUSY_COMPANY_NOT_FOUND` |\n\nGuard: skipped unless `confirmMutating` = `yes`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"a2b3c4d5e6f7481900aabbccddeeffbb"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"companyCode\":\"COMP0098\",\"displayName\":\"Example Stores\",\"provider\":\"access\",\"sqlServer\":null,\"access\":{\"dataFolder\":\"C:\\\\BusyWin\\\\DATA\"},\"enabled\":false,\"lastValidatedUtc\":null,\"lastValidationCode\":null,\"allowedFinancialYears\":[\"2026\"],\"foundFinancialYears\":[],\"updatedUtc\":\"2026-09-26T05:50:00.0000000+00:00\"},\"metadata\":{}}"}],"_postman_id":"984fbbe4-ba83-1de2-af69-b9fda8631565"},{"name":"⚠ BUSY company – test connection","id":"1244f64d-0400-6a9b-187a-a620b5243264","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}/test","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}/test</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Opens BUSY with the stored configuration of <code>{{targetCompanyCode}}</code> (read only) and checks the company and each allowed financial year. It <strong>records the result</strong> on the company (<code>lastValidatedUtc</code>, <code>lastValidationCode</code>, <code>foundFinancialYears</code>), which is why it is in this folder. Bounded to 45 s; one BUSY read runs at a time on the PC. No body.</p>\n<p><code>data.code</code> in the 200 answer: <code>OK</code>; <code>BUSY_ALLOWED_YEAR_UNAVAILABLE</code> (an allowed year has no BUSY data); <code>BUSY_SECRET_UNAVAILABLE</code> (the stored SQL password cannot be opened); or a connection failure such as <code>BUSY_UNAVAILABLE</code>, <code>BUSY_COMPANY_NOT_FOUND</code>, <code>BUSY_COMPANY_LOCKED</code>, <code>BUSY_SCHEMA_UNSUPPORTED</code>. A test that could not connect is still HTTP 200 with <code>success: true</code>: the test ran and its result is the data.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body / code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td><code>data</code>: <code>{ \"code\", \"message\", \"busyCompanyName\", \"foundFinancialYears\", \"unavailableYears\", \"company\" }</code>; <code>metadata</code>: <code>{}</code></td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>BUSY_COMPANY_NOT_FOUND</code> (no such company in AI Zeny)</td>\n</tr>\n<tr>\n<td>504</td>\n<td><code>BUSY_TIMEOUT</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","companies","{{targetCompanyCode}}","test"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"b7c2a509-70c5-5df6-6c38-2e67ca065c68","name":"200 OK – test passed","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}/test","description":"**Local** · `POST {{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}/test` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually.** Opens BUSY with the stored configuration of `{{targetCompanyCode}}` (read only) and checks the company and each allowed financial year. It **records the result** on the company (`lastValidatedUtc`, `lastValidationCode`, `foundFinancialYears`), which is why it is in this folder. Bounded to 45 s; one BUSY read runs at a time on the PC. No body.\n\n`data.code` in the 200 answer: `OK`; `BUSY_ALLOWED_YEAR_UNAVAILABLE` (an allowed year has no BUSY data); `BUSY_SECRET_UNAVAILABLE` (the stored SQL password cannot be opened); or a connection failure such as `BUSY_UNAVAILABLE`, `BUSY_COMPANY_NOT_FOUND`, `BUSY_COMPANY_LOCKED`, `BUSY_SCHEMA_UNSUPPORTED`. A test that could not connect is still HTTP 200 with `success: true`: the test ran and its result is the data.\n\n| Status | Body / code |\n|---|---|\n| 200 | `data`: `{ \"code\", \"message\", \"busyCompanyName\", \"foundFinancialYears\", \"unavailableYears\", \"company\" }`; `metadata`: `{}` |\n| 404 | `BUSY_COMPANY_NOT_FOUND` (no such company in AI Zeny) |\n| 504 | `BUSY_TIMEOUT` |\n\nGuard: skipped unless `confirmMutating` = `yes`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"b3c4d5e6f7a8491011aabbccddeeffcc"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"code\": \"OK\",\n    \"message\": \"Connected to BUSY. Every allowed financial year is available.\",\n    \"busyCompanyName\": \"Example Traders\",\n    \"foundFinancialYears\": [\"2025\", \"2026\"],\n    \"unavailableYears\": [],\n    \"company\": {\n      \"companyCode\": \"COMP0099\", \"displayName\": \"Example Traders\", \"provider\": \"sqlServer\",\n      \"sqlServer\": { \"server\": \"BUSYSERVER\\\\SQLEXPRESS\", \"port\": null, \"authentication\": \"sqlLogin\", \"userName\": \"busyreader\", \"hasPassword\": true, \"encrypt\": true, \"trustServerCertificate\": true },\n      \"access\": null, \"enabled\": true,\n      \"lastValidatedUtc\": \"2026-09-26T05:51:00.0000000+00:00\", \"lastValidationCode\": \"OK\",\n      \"allowedFinancialYears\": [\"2025\", \"2026\"], \"foundFinancialYears\": [\"2025\", \"2026\"],\n      \"updatedUtc\": \"2026-09-26T05:51:00.0000000+00:00\"\n    }\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"1244f64d-0400-6a9b-187a-a620b5243264"},{"name":"⚠ BUSY company – delete","id":"24262542-0382-baf2-3ae7-8f9664d48390","request":{"method":"DELETE","header":[],"url":"{{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}","description":"<p><strong>Local</strong> · <code>DELETE {{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually. Destructive for the AI Zeny configuration.</strong> Removes the company <code>{{targetCompanyCode}}</code> from AI Zeny on this PC, including its sealed SQL password. BUSY's own data is never touched. Relay commands and V1 operations for that code answer <code>COMPANY_NOT_CONFIGURED</code> afterwards; add it again with <em>create</em> to undo. No body.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body / code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the removed company (as it was)</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>BUSY_COMPANY_NOT_FOUND</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>. <code>targetCompanyCode</code> is empty by default, so an accidental send cannot hit a company.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","companies","{{targetCompanyCode}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"4bf28300-7351-4a10-b145-11ec8f84924f","name":"200 OK – removed","originalRequest":{"method":"DELETE","header":[],"url":"{{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}","description":"**Local** · `DELETE {{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually. Destructive for the AI Zeny configuration.** Removes the company `{{targetCompanyCode}}` from AI Zeny on this PC, including its sealed SQL password. BUSY's own data is never touched. Relay commands and V1 operations for that code answer `COMPANY_NOT_CONFIGURED` afterwards; add it again with *create* to undo. No body.\n\n| Status | Body / code |\n|---|---|\n| 200 | the removed company (as it was) |\n| 404 | `BUSY_COMPANY_NOT_FOUND` |\n\nGuard: skipped unless `confirmMutating` = `yes`. `targetCompanyCode` is empty by default, so an accidental send cannot hit a company."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"c4d5e6f7a8b9401122aabbccddeeffdd","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\"success\":true,\"data\":{\"companyCode\":\"COMP0098\",\"displayName\":\"Example Stores\",\"provider\":\"access\",\"sqlServer\":null,\"access\":{\"dataFolder\":\"C:\\\\BusyWin\\\\DATA\"},\"enabled\":false,\"lastValidatedUtc\":null,\"lastValidationCode\":null,\"allowedFinancialYears\":[\"2026\"],\"foundFinancialYears\":[],\"updatedUtc\":\"2026-09-26T05:50:00.0000000+00:00\"},\"metadata\":{}}"},{"id":"ae7ca01e-d5c7-d0e1-7351-445f4b3f23b5","name":"404 BUSY_COMPANY_NOT_FOUND","originalRequest":{"method":"DELETE","header":[],"url":"{{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}","description":"**Local** · `DELETE {{baseUrl}}/api/v1/busy/companies/{{targetCompanyCode}}` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually. Destructive for the AI Zeny configuration.** Removes the company `{{targetCompanyCode}}` from AI Zeny on this PC, including its sealed SQL password. BUSY's own data is never touched. Relay commands and V1 operations for that code answer `COMPANY_NOT_CONFIGURED` afterwards; add it again with *create* to undo. No body.\n\n| Status | Body / code |\n|---|---|\n| 200 | the removed company (as it was) |\n| 404 | `BUSY_COMPANY_NOT_FOUND` |\n\nGuard: skipped unless `confirmMutating` = `yes`. `targetCompanyCode` is empty by default, so an accidental send cannot hit a company."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"d5e6f7a8b9c0411233aabbccddeeffee"}],"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"BUSY_COMPANY_NOT_FOUND\",\"message\":\"No company has that code on this PC.\"},\"requestId\":\"d5e6f7a8b9c0411233aabbccddeeffee\"}}"}],"_postman_id":"24262542-0382-baf2-3ae7-8f9664d48390"},{"name":"⚠ Saved query – create","id":"1e9be992-2001-b721-5f55-640d11a8f417","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"name\": \"Product Report\",\n  \"sqlServerQuery\": \"SELECT Code, Name FROM Master1 WHERE MasterType = 6 AND Code >= @fromCode AND (@name IS NULL OR Name = @name) ORDER BY Code\",\n  \"accessQuery\": \"SELECT Code, Name FROM Master1 WHERE MasterType = 6 AND Code >= @fromCode AND (@name IS NULL OR Name = @name) ORDER BY Code\",\n  \"parameters\": [\n    { \"name\": \"fromCode\", \"type\": \"integer\", \"required\": true },\n    { \"name\": \"name\", \"type\": \"text\", \"required\": false }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/saved-queries","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/saved-queries</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Saves a query (the example becomes <code>Product-Report</code>). At least one definition; each must pass the read-only boundary for its own database; both must use the same <code>@placeholders</code>; <code>parameters</code> declares each placeholder once. Nothing is executed.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body / code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the query as stored, <code>revision: 1</code></td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>BAD_REQUEST</code>, <code>SAVED_QUERY_INVALID</code> (field <code>name</code>, <code>sqlServerQuery</code>, <code>accessQuery</code>, <code>parameters</code>, <code>expectedRevision</code>), <code>CUSTOM_SQL_REJECTED</code></td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>SAVED_QUERY_NAME_TAKEN</code>, <code>SAVED_QUERY_NAME_RESERVED</code></td>\n</tr>\n<tr>\n<td>413</td>\n<td><code>REQUEST_TOO_LARGE</code> (over 128 KiB)</td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","saved-queries"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"1e9be992-2001-b721-5f55-640d11a8f417"},{"name":"⚠ Saved query – change","id":"97409a42-95de-d5f0-5e73-82dfdfe7a987","request":{"method":"PUT","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"name\": \"{{savedQueryName}}\",\n  \"sqlServerQuery\": \"SELECT Code, Name, PrintName FROM Master1 WHERE MasterType = 6 AND Code >= @fromCode AND (@name IS NULL OR Name = @name) ORDER BY Code\",\n  \"accessQuery\": \"SELECT Code, Name, PrintName FROM Master1 WHERE MasterType = 6 AND Code >= @fromCode AND (@name IS NULL OR Name = @name) ORDER BY Code\",\n  \"parameters\": [\n    { \"name\": \"fromCode\", \"type\": \"integer\", \"required\": true },\n    { \"name\": \"name\", \"type\": \"text\", \"required\": false }\n  ],\n  \"expectedRevision\": {{savedQueryRevision}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}","description":"<p><strong>Local</strong> · <code>PUT {{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Replaces <code>{{savedQueryName}}</code> when it is still at <code>expectedRevision</code> (run <em>View one saved query</em> or <em>Open one saved query</em> first; it stores the revision). A different <code>name</code> renames it explicitly (callers of the old name then get 404). A <strong>PIN-protected</strong> query needs its PIN: put it in <code>savedQueryPin</code> as a current value (the pre-request script adds <code>pin</code>; it is cleared after the send). The change keeps the query's PIN; set, change or remove the PIN with <em>⚠ Saved query – set, change or remove PIN</em> (<code>newPin</code> here is refused).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body / code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the query as stored (<code>revision</code> + 1)</td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>BAD_REQUEST</code>, <code>SAVED_QUERY_INVALID</code>, <code>CUSTOM_SQL_REJECTED</code></td>\n</tr>\n<tr>\n<td>403</td>\n<td><code>SAVED_QUERY_PIN_REQUIRED</code>, <code>SAVED_QUERY_PIN_INCORRECT</code> (checked before the revision; nothing changed)</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>SAVED_QUERY_NOT_FOUND</code></td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>SAVED_QUERY_CONFLICT</code> (changed or deleted since it was read; nothing overwritten), <code>SAVED_QUERY_NAME_TAKEN</code>, <code>SAVED_QUERY_NAME_RESERVED</code>, <code>SAVED_QUERY_PIN_UNREADABLE</code></td>\n</tr>\n<tr>\n<td>429</td>\n<td><code>SAVED_QUERY_PIN_THROTTLED</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","saved-queries","{{savedQueryName}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"97409a42-95de-d5f0-5e73-82dfdfe7a987"},{"name":"⚠ Saved query – delete","id":"f17f9536-a8fb-06d4-add1-7fe53bc1e9fb","request":{"method":"DELETE","header":[],"url":"{{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}?revision={{savedQueryRevision}}","description":"<p><strong>Local</strong> · <code>DELETE {{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Deletes <code>{{savedQueryName}}</code> at <code>?revision=</code> (the revision you read). Apps that run it by name then get <code>404 NOT_FOUND</code>. BUSY data is never touched. A <strong>PIN-protected</strong> query is deleted only with its PIN: put it in <code>savedQueryPin</code> as a current value; the pre-request script sends the body <code>{ \"pin\": \"…\" }</code> (never in the URL) and the PIN is cleared after the send. Without the PIN nobody can delete a protected query and save other SQL under its name; a forgotten PIN therefore cannot be bypassed here either.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body / code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the deleted query's list row</td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>SAVED_QUERY_INVALID</code> (field <code>revision</code>), <code>BAD_REQUEST</code></td>\n</tr>\n<tr>\n<td>403</td>\n<td><code>SAVED_QUERY_PIN_REQUIRED</code>, <code>SAVED_QUERY_PIN_INCORRECT</code> (nothing deleted)</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>SAVED_QUERY_NOT_FOUND</code></td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>SAVED_QUERY_CONFLICT</code>, <code>SAVED_QUERY_PIN_UNREADABLE</code></td>\n</tr>\n<tr>\n<td>429</td>\n<td><code>SAVED_QUERY_PIN_THROTTLED</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","saved-queries","{{savedQueryName}}"],"host":["{{baseUrl}}"],"query":[{"description":{"content":"<p>The revision you read; any other is refused (409 SAVED_QUERY_CONFLICT).</p>\n","type":"text/plain"},"key":"revision","value":"{{savedQueryRevision}}"}],"variable":[]}},"response":[],"_postman_id":"f17f9536-a8fb-06d4-add1-7fe53bc1e9fb"},{"name":"⚠ Script – create","id":"af6550f9-fb6f-849a-1389-c03faadc917d","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"name\": \"{{scriptName}}\",\n  \"kind\": \"named\",\n  \"source\": \"function main(input) {\\n  const branches = api.run('busy.branches.list').data;\\n  return { company: input.company.code, branches: branches.length };\\n}\",\n  \"enabled\": true,\n  \"allowHttp\": false,\n  \"assignments\": [ { \"companyCode\": \"{{companyCode}}\", \"enabled\": true } ]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/scripts","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/scripts</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Saves a script. A transform assigns <code>{ companyCode, operation (e.g. busy.material-centers.list), role (default | variant), enabled }</code>; a named script <code>{ companyCode, enabled }</code>. At most one default per company and operation across all scripts. A script whose check fails (syntax, no <code>function main</code>) can be saved only with <code>enabled: false</code>.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body / code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the script as stored (<code>revision: 1</code>, <code>check</code>)</td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>SCRIPT_INVALID</code> (field <code>name</code>, <code>kind</code>, <code>source</code>, <code>assignments[i]…</code>), <code>SCRIPT_SYNTAX_ERROR</code> (line and column in the message), <code>BAD_REQUEST</code></td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>SCRIPT_NAME_TAKEN</code>, <code>SCRIPT_ASSIGNMENT_CONFLICT</code></td>\n</tr>\n<tr>\n<td>413</td>\n<td><code>REQUEST_TOO_LARGE</code> (bodies up to 1 MiB)</td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","scripts"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"af6550f9-fb6f-849a-1389-c03faadc917d"},{"name":"⚠ Script – change","id":"ff888fdb-bebc-5f74-e351-a6556a9e151f","request":{"method":"PUT","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"name\": \"{{scriptName}}\",\n  \"kind\": \"named\",\n  \"source\": \"function main(input) {\\n  const branches = api.run('busy.branches.list').data;\\n  return { company: input.company.code, branches: branches.length, names: branches.map(b => b.branch_name) };\\n}\",\n  \"enabled\": true,\n  \"allowHttp\": false,\n  \"assignments\": [ { \"companyCode\": \"{{companyCode}}\", \"enabled\": true } ],\n  \"expectedRevision\": {{scriptRevision}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/scripts/{{scriptName}}","description":"<p><strong>Local</strong> · <code>PUT {{baseUrl}}/api/v1/busy/scripts/{{scriptName}}</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Replaces the script (and may rename it) when it is still at <code>expectedRevision</code> (the revision you read; <em>View one script</em> stores it in <code>scriptRevision</code>). A concurrent change is <code>409 SCRIPT_CONFLICT</code> and nothing is overwritten. Same body rules and refusals as <em>create</em>, plus <code>404 SCRIPT_NOT_FOUND</code>.</p>\n<p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","scripts","{{scriptName}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"ff888fdb-bebc-5f74-e351-a6556a9e151f"},{"name":"⚠ Script – delete","id":"bce594a3-0324-a12d-9f9f-1283bfe53f39","request":{"method":"DELETE","header":[],"url":"{{baseUrl}}/api/v1/busy/scripts/{{scriptName}}?revision={{scriptRevision}}","description":"<p><strong>Local</strong> · <code>DELETE {{baseUrl}}/api/v1/busy/scripts/{{scriptName}}</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Deletes <code>{{scriptName}}</code> and its assignments at <code>?revision=</code>. Company defaults it held stop applying (those answers return to the standard data); callers that name it get <code>404 SCRIPT_NOT_FOUND</code>. BUSY data is never touched.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body / code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the deleted script's list row</td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>SCRIPT_INVALID</code> (field <code>revision</code>)</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>SCRIPT_NOT_FOUND</code></td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>SCRIPT_CONFLICT</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","scripts","{{scriptName}}"],"host":["{{baseUrl}}"],"query":[{"description":{"content":"<p>The revision you read; any other is refused (409 SCRIPT_CONFLICT).</p>\n","type":"text/plain"},"key":"revision","value":"{{scriptRevision}}"}],"variable":[]}},"response":[],"_postman_id":"bce594a3-0324-a12d-9f9f-1283bfe53f39"},{"name":"⚠ Saved query – set, change or remove PIN","id":"0c9b3270-083c-df2a-1b3c-bde8b3953b0c","request":{"method":"PUT","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"pin\": \"{{savedQueryPin}}\",\n  \"newPin\": \"{{savedQueryNewPin}}\",\n  \"expectedRevision\": {{savedQueryRevision}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}/pin","description":"<p><strong>Local</strong> · <code>PUT {{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}/pin</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)</p>\n<p><strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Sets, changes or removes the query's own PIN, which guards <strong>viewing and changing its SQL only</strong> (docs/LOCAL-API.md 5r \"Source PIN\"). Running the query by name, scripts, Google Sheets exports, schedules and the Cloud Relay never need the PIN.</p>\n<p>Body <code>{ pin, newPin, expectedRevision }</code>, built by the pre-request script from <strong>current values only</strong> (both are cleared after the send; never put a real PIN in the collection or a synced value):</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Action</th>\n<th><code>savedQueryPin</code></th>\n<th><code>savedQueryNewPin</code></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Set (query without a PIN)</td>\n<td>empty (no <code>pin</code> sent)</td>\n<td>the new PIN, 4-6 digits</td>\n</tr>\n<tr>\n<td>Change</td>\n<td>the current PIN</td>\n<td>the new PIN</td>\n</tr>\n<tr>\n<td>Remove</td>\n<td>the current PIN</td>\n<td>empty (<code>newPin: null</code>)</td>\n</tr>\n</tbody>\n</table>\n</div><p><code>expectedRevision</code> = <code>savedQueryRevision</code> (run <em>View one saved query</em> or <em>Open one saved query</em> first). Each change is a new revision; the SQL, parameters and name are not touched. The current PIN is checked <strong>before</strong> the revision.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body / code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the list row <code>{ name, sqlServer, access, parameters, revision, createdUtc, updatedUtc, protected }</code> (no SQL); stores <code>savedQueryRevision</code></td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>BAD_REQUEST</code>; <code>SAVED_QUERY_INVALID</code> (<code>field: newPin</code> — \"A query PIN is 4 to 6 digits.\", or nothing to remove; <code>field: expectedRevision</code>)</td>\n</tr>\n<tr>\n<td>403</td>\n<td><code>SAVED_QUERY_PIN_REQUIRED</code>, <code>SAVED_QUERY_PIN_INCORRECT</code> (<code>field: pin</code>)</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>SAVED_QUERY_NOT_FOUND</code></td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>SAVED_QUERY_CONFLICT</code> (changed since read; nothing overwritten), <code>SAVED_QUERY_PIN_UNREADABLE</code></td>\n</tr>\n<tr>\n<td>429</td>\n<td><code>SAVED_QUERY_PIN_THROTTLED</code></td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>No recovery:</strong> a forgotten PIN cannot be shown or reset, and a protected query can then never be viewed, changed or deleted (a delete needs the PIN too). Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>. Examples use synthetic values only.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","saved-queries","{{savedQueryName}}","pin"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"bcc9bc4b-43a8-6846-3d0a-174ac1fc45ae","name":"200 – PIN changed: the list row, no SQL (synthetic)","originalRequest":{"method":"PUT","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"pin\": \"{{savedQueryPin}}\",\n  \"newPin\": \"{{savedQueryNewPin}}\",\n  \"expectedRevision\": {{savedQueryRevision}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}/pin","description":"**Local** · `PUT {{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}/pin` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually.** Sets, changes or removes the query's own PIN, which guards **viewing and changing its SQL only** (docs/LOCAL-API.md 5r \"Source PIN\"). Running the query by name, scripts, Google Sheets exports, schedules and the Cloud Relay never need the PIN.\n\nBody `{ pin, newPin, expectedRevision }`, built by the pre-request script from **current values only** (both are cleared after the send; never put a real PIN in the collection or a synced value):\n\n| Action | `savedQueryPin` | `savedQueryNewPin` |\n|---|---|---|\n| Set (query without a PIN) | empty (no `pin` sent) | the new PIN, 4-6 digits |\n| Change | the current PIN | the new PIN |\n| Remove | the current PIN | empty (`newPin: null`) |\n\n`expectedRevision` = `savedQueryRevision` (run *View one saved query* or *Open one saved query* first). Each change is a new revision; the SQL, parameters and name are not touched. The current PIN is checked **before** the revision.\n\n| Status | Body / code |\n|---|---|\n| 200 | the list row `{ name, sqlServer, access, parameters, revision, createdUtc, updatedUtc, protected }` (no SQL); stores `savedQueryRevision` |\n| 400 | `BAD_REQUEST`; `SAVED_QUERY_INVALID` (`field: newPin` — \"A query PIN is 4 to 6 digits.\", or nothing to remove; `field: expectedRevision`) |\n| 403 | `SAVED_QUERY_PIN_REQUIRED`, `SAVED_QUERY_PIN_INCORRECT` (`field: pin`) |\n| 404 | `SAVED_QUERY_NOT_FOUND` |\n| 409 | `SAVED_QUERY_CONFLICT` (changed since read; nothing overwritten), `SAVED_QUERY_PIN_UNREADABLE` |\n| 429 | `SAVED_QUERY_PIN_THROTTLED` |\n\n**No recovery:** a forgotten PIN cannot be shown or reset, and a protected query can then never be viewed, changed or deleted (a delete needs the PIN too). Guard: skipped unless `confirmMutating` = `yes`. Examples use synthetic values only."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"name\": \"Margins\",\n    \"sqlServer\": true,\n    \"access\": true,\n    \"parameters\": [ { \"name\": \"fromCode\", \"type\": \"integer\", \"required\": true } ],\n    \"revision\": 4,\n    \"createdUtc\": \"2026-10-16T09:00:00+00:00\",\n    \"updatedUtc\": \"2026-10-16T09:45:00+00:00\",\n    \"protected\": true\n  },\n  \"metadata\": {}\n}"},{"id":"99cd5da7-63cb-a9da-ce89-d1f94c4a7503","name":"400 – new PIN not 4-6 digits (synthetic)","originalRequest":{"method":"PUT","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"pin\": \"{{savedQueryPin}}\",\n  \"newPin\": \"{{savedQueryNewPin}}\",\n  \"expectedRevision\": {{savedQueryRevision}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}/pin","description":"**Local** · `PUT {{baseUrl}}/api/v1/busy/saved-queries/{{savedQueryName}}/pin` · Bearer `{{localApiToken}}` (collection auth) · **Changes AI Zeny on the PC** (not BUSY; guarded by `confirmMutating`)\n\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — run manually.** Sets, changes or removes the query's own PIN, which guards **viewing and changing its SQL only** (docs/LOCAL-API.md 5r \"Source PIN\"). Running the query by name, scripts, Google Sheets exports, schedules and the Cloud Relay never need the PIN.\n\nBody `{ pin, newPin, expectedRevision }`, built by the pre-request script from **current values only** (both are cleared after the send; never put a real PIN in the collection or a synced value):\n\n| Action | `savedQueryPin` | `savedQueryNewPin` |\n|---|---|---|\n| Set (query without a PIN) | empty (no `pin` sent) | the new PIN, 4-6 digits |\n| Change | the current PIN | the new PIN |\n| Remove | the current PIN | empty (`newPin: null`) |\n\n`expectedRevision` = `savedQueryRevision` (run *View one saved query* or *Open one saved query* first). Each change is a new revision; the SQL, parameters and name are not touched. The current PIN is checked **before** the revision.\n\n| Status | Body / code |\n|---|---|\n| 200 | the list row `{ name, sqlServer, access, parameters, revision, createdUtc, updatedUtc, protected }` (no SQL); stores `savedQueryRevision` |\n| 400 | `BAD_REQUEST`; `SAVED_QUERY_INVALID` (`field: newPin` — \"A query PIN is 4 to 6 digits.\", or nothing to remove; `field: expectedRevision`) |\n| 403 | `SAVED_QUERY_PIN_REQUIRED`, `SAVED_QUERY_PIN_INCORRECT` (`field: pin`) |\n| 404 | `SAVED_QUERY_NOT_FOUND` |\n| 409 | `SAVED_QUERY_CONFLICT` (changed since read; nothing overwritten), `SAVED_QUERY_PIN_UNREADABLE` |\n| 429 | `SAVED_QUERY_PIN_THROTTLED` |\n\n**No recovery:** a forgotten PIN cannot be shown or reset, and a protected query can then never be viewed, changed or deleted (a delete needs the PIN too). Guard: skipped unless `confirmMutating` = `yes`. Examples use synthetic values only."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": { \"code\": \"SAVED_QUERY_INVALID\", \"message\": \"A query PIN is 4 to 6 digits.\", \"field\": \"newPin\" },\n    \"requestId\": \"00000000000000000000000000000000\"\n  }\n}"}],"_postman_id":"0c9b3270-083c-df2a-1b3c-bde8b3953b0c"},{"name":"⚠ PUT company webhook (Local configuration change)","id":"9be4c231-b20b-1373-ffbd-715dc7612dd9","request":{"method":"PUT","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"url\":\"{{writeWebhookUrl}}\"}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/companies/{{companyCode}}/write-webhook","description":"<p>Protected Local configuration mutation, never relayed. Body must contain exactly url: a real HTTPS URL (max 4096 characters, no userinfo/fragment/control characters) or null to clear. Missing/unknown members are refused. This template uses writeWebhookUrl, intentionally unset; set it privately as a current-only value. The request guard also requires confirmWebhookChange=yes for each send. No real URL belongs in saved examples. Jobs snapshot the company-wide destination at acceptance; no backfill. Duplicate events share eventId; delivery has 15-second timeout and at most five event-only attempts. Do not run collection-wide.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","companies","{{companyCode}}","write-webhook"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"aae8c643-e6c6-6329-9f1a-fbb6854ae387","name":"200 – company webhook setting saved (URL never returned)","originalRequest":{"method":"PUT","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"url\":\"{{writeWebhookUrl}}\"}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/companies/{{companyCode}}/write-webhook","description":"Protected Local configuration mutation, never relayed. Body must contain exactly url: a real HTTPS URL (max 4096 characters, no userinfo/fragment/control characters) or null to clear. Missing/unknown members are refused. This template uses writeWebhookUrl, intentionally unset; set it privately as a current-only value. The request guard also requires confirmWebhookChange=yes for each send. No real URL belongs in saved examples. Jobs snapshot the company-wide destination at acceptance; no backfill. Duplicate events share eventId; delivery has 15-second timeout and at most five event-only attempts. Do not run collection-wide."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"companyCode\": \"COMP0002\",\n    \"configured\": true\n  },\n  \"metadata\": {}\n}"},{"id":"42d3ca2e-8109-c0b1-1196-eaa91b75d504","name":"400 – webhook body refused (synthetic)","originalRequest":{"method":"PUT","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"url\":\"{{writeWebhookUrl}}\"}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/companies/{{companyCode}}/write-webhook","description":"Protected Local configuration mutation, never relayed. Body must contain exactly url: a real HTTPS URL (max 4096 characters, no userinfo/fragment/control characters) or null to clear. Missing/unknown members are refused. This template uses writeWebhookUrl, intentionally unset; set it privately as a current-only value. The request guard also requires confirmWebhookChange=yes for each send. No real URL belongs in saved examples. Jobs snapshot the company-wide destination at acceptance; no backfill. Duplicate events share eventId; delivery has 15-second timeout and at most five event-only attempts. Do not run collection-wide."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"requestId\": \"synthetic-read-002\",\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"The body is { url: HTTPS URL or null }; no user information or fragment is allowed.\"\n    }\n  }\n}"}],"_postman_id":"9be4c231-b20b-1373-ffbd-715dc7612dd9"}],"id":"65ff8503-cb05-498e-9d65-d5991ddb027b","description":"<p>Requests that change AI Zeny on the PC, never BUSY's books: update check, Pusher restart, token regeneration, BUSY company setup, saved queries, scripts, schedules and message rows. Each is skipped unless <code>confirmMutating</code> = <code>yes</code>, and resets it after one send. Never run this folder in the Collection Runner or a monitor. Local only.</p>\n","_postman_id":"65ff8503-cb05-498e-9d65-d5991ddb027b","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ PC Settings — Schedules (changes AI Zeny, not BUSY)","item":[{"name":"⚠ Create a schedule","id":"196bace4-3f61-0c2c-b05f-c74e999d99cd","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"name\": \"{{scheduleName}}\",\n  \"scriptName\": \"{{scheduleScriptName}}\",\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"parameters\": { \"minAmount\": 1000 },\n  \"timeZone\": \"Asia/Kolkata\",\n  \"primaryTime\": \"09:00\",\n  \"retryTimes\": [\"10:00\", \"11:00\"]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/schedules","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/schedules</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Creates a daily schedule of a saved <strong>named script</strong> (docs/LOCAL-API.md 5t). From then on the <strong>AI Zeny Host runs it by itself</strong> every day: at the primary time, and at each retry time only while that day has not succeeded. A time missed while the PC or service was down runs once as a catch-up until the window closes (last time + 15 minutes, never past midnight); later it is recorded as missed. Missed days are never replayed.</p>\n<p>Members: <code>name</code> (letters, digits, <code>-</code>, <code>_</code>; spaces become <code>-</code>; unique without case), <code>scriptName</code> (an enabled named script assigned to the company), <code>companyCode</code> (configured and enabled), <code>financialYear</code> (four-digit, allowed for the company), optional <code>parameters</code> (a JSON object, ≤ 16 KiB, stored encrypted; the script reads <code>input.parameters</code>), <code>timeZone</code> (an id from <em>Time zones</em>), <code>primaryTime</code> (<code>HH:mm</code>), <code>retryTimes</code> (0-2, each later than the one before, same day). Unknown members are refused.</p>\n<p>⚠ The script runs for real at its times. It may call external services (for example to send a message) — use a harmless script when testing.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the schedule with its parameters and <code>nextRunLocal</code></td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>SCHEDULE_INVALID</code> with <code>field</code></td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>SCHEDULE_NAME_TAKEN</code>, <code>SCRIPT_NOT_ASSIGNED</code>, <code>SCRIPT_DISABLED</code></td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>SCRIPT_NOT_FOUND</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","schedules"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"196bace4-3f61-0c2c-b05f-c74e999d99cd"},{"name":"⚠ Change a schedule","id":"ee75e373-ab5a-abde-8e15-c52a71e6849a","request":{"method":"PUT","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"name\": \"{{scheduleName}}\",\n  \"scriptName\": \"{{scheduleScriptName}}\",\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"parameters\": { \"minAmount\": 2000 },\n  \"timeZone\": \"Asia/Kolkata\",\n  \"primaryTime\": \"09:30\",\n  \"retryTimes\": [\"10:30\"],\n  \"expectedRevision\": {{scheduleRevision}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/schedules/{{scheduleName}}","description":"<p><strong>Local</strong> · <code>PUT {{baseUrl}}/api/v1/busy/schedules/{{scheduleName}}</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Replaces every member (an absent <code>parameters</code> clears them; <code>name</code> may rename) if <code>expectedRevision</code> is still the schedule's revision (read it from <em>Get one schedule</em>; <code>scheduleRevision</code> is set by create and by this request). A run in progress is not stopped: it ends with the settings it started with. New times apply from now on — a time already past today is not run.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the schedule</td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>SCHEDULE_INVALID</code> (for example <code>expectedRevision</code> missing)</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>SCHEDULE_NOT_FOUND</code></td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>SCHEDULE_CONFLICT</code> — changed elsewhere, nothing overwritten</td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","schedules","{{scheduleName}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"ee75e373-ab5a-abde-8e15-c52a71e6849a"},{"name":"⚠ Pause a schedule","id":"ae3eb660-70d8-5539-b9f0-2d8da3782d8a","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{ \"mode\": \"tomorrow\" }","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/schedules/{{scheduleName}}/pause","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/schedules/{{scheduleName}}/pause</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> <code>mode</code>: <code>today</code>, <code>tomorrow</code>, <code>date</code> (with <code>\"date\": \"YYYY-MM-DD\"</code>, today or later in the schedule's zone; at most 31 dates ahead) or <code>permanent</code> (until <em>Resume</em>). A date pause expires by itself. A pause stops <strong>automatic</strong> runs only: a run in progress continues, <em>Run now</em> still works, and paused days are recorded as <code>paused</code> and never made up.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the schedule with <code>paused</code></td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>SCHEDULE_INVALID</code> (<code>mode</code>, <code>date</code>)</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>SCHEDULE_NOT_FOUND</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","schedules","{{scheduleName}}","pause"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"ae3eb660-70d8-5539-b9f0-2d8da3782d8a"},{"name":"⚠ Resume a schedule","id":"2d206fdd-ef32-a22e-db16-6829b3211d7a","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/busy/schedules/{{scheduleName}}/resume","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/schedules/{{scheduleName}}/resume</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Clears every pause (dates and permanent). Nothing from the paused days is replayed; today's remaining times follow the normal window rules (a time already past runs once as a catch-up only while the window is open).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the schedule</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>SCHEDULE_NOT_FOUND</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","schedules","{{scheduleName}}","resume"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"2d206fdd-ef32-a22e-db16-6829b3211d7a"},{"name":"⚠ Run now","id":"c75e47fa-bd47-7815-c463-7842fac13d8d","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/busy/schedules/{{scheduleName}}/run","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/schedules/{{scheduleName}}/run</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Starts a manual run of the schedule's script with its company, year and parameters, even while paused. It is recorded with <code>trigger: manual</code>, never counts as the day's scheduled success and never consumes a scheduled time. The run goes on in the Host; follow it with <em>Get one run</em> (<code>scheduleRunId</code> is set here).</p>\n<p>⚠ The script really runs and may call external services.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td><code>{ \"success\": true, \"data\": { \"runId\": 42, \"status\": \"queued\" }, \"metadata\": {} }</code></td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>SCHEDULE_RUN_ACTIVE</code> — a run of this schedule is already queued or running</td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>SCHEDULE_NOT_FOUND</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","schedules","{{scheduleName}}","run"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"c75e47fa-bd47-7815-c463-7842fac13d8d"},{"name":"⚠ Stop a run","id":"0237b331-66c2-fda8-e935-651e98bc589b","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/busy/schedule-runs/{{scheduleRunId}}/stop","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/schedule-runs/{{scheduleRunId}}/stop</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Stops <strong>only this run</strong>, including the API and query reads it started; it is recorded <code>cancelled</code> (<code>SCHEDULE_RUN_CANCELLED</code>). The schedule stays active and its later retries and days still run — Stop never pauses. Anything the script already did outside AI Zeny (for example a message it sent) cannot be undone.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the run as it stands (a queued run is already <code>cancelled</code>; a running one becomes <code>cancelled</code> when the engine has ended it, normally within a second)</td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>SCHEDULE_RUN_NOT_ACTIVE</code></td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>SCHEDULE_RUN_NOT_FOUND</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","schedule-runs","{{scheduleRunId}}","stop"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"0237b331-66c2-fda8-e935-651e98bc589b"},{"name":"⚠ Delete a schedule","id":"fdebe180-8df6-06d5-623b-4226e97a3539","request":{"method":"DELETE","header":[],"url":"{{baseUrl}}/api/v1/busy/schedules/{{scheduleName}}?revision={{scheduleRevision}}","description":"<p><strong>Local</strong> · <code>DELETE {{baseUrl}}/api/v1/busy/schedules/{{scheduleName}}</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Deletes the schedule at the revision you read; its history stays. Refused while a run of it is queued or running (stop it or let it end first).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the deleted schedule</td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>SCHEDULE_RUN_ACTIVE</code>, <code>SCHEDULE_CONFLICT</code></td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>SCHEDULE_NOT_FOUND</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","schedules","{{scheduleName}}"],"host":["{{baseUrl}}"],"query":[{"description":{"content":"<p>the revision you read</p>\n","type":"text/plain"},"key":"revision","value":"{{scheduleRevision}}"}],"variable":[]}},"response":[],"_postman_id":"fdebe180-8df6-06d5-623b-4226e97a3539"}],"id":"fdfea1c0-cfd1-4177-bc33-0d03ba9cfb0b","description":"<p>Guarded by <code>confirmMutating</code>; changes AI Zeny on the PC, not BUSY. Part of ⚠ PC Settings &amp; Management.</p>\n","_postman_id":"fdfea1c0-cfd1-4177-bc33-0d03ba9cfb0b","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ PC Settings — Messages (changes AI Zeny, not BUSY)","item":[{"name":"⚠ Insert message rows","id":"a5af8cae-2d2e-fe43-bc15-5851a814f5f7","request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"rows\": [\n    { \"recipientId\": \"ACC-TEST-1\", \"batchId\": \"postman-test\", \"idempotencyKey\": \"postman-test-1\", \"custom1\": \"synthetic\" }\n  ],\n  \"onDuplicate\": \"return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/messages/email","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/messages/email</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Stores 1-500 rows (≤ 8 MiB), all or nothing. Only <code>status</code> (default <code>pending</code>), the system id, timestamps and revision are always present; every other field is optional (docs/LOCAL-API.md 5u field table). Use synthetic values; never real recipients. Nothing is sent.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td><code>{ rows, inserted, duplicates }</code></td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>MESSAGE_INVALID</code> with <code>field</code> (e.g. <code>rows[0].companyCode</code>)</td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>MESSAGE_DUPLICATE</code> (without <code>onDuplicate: \"return\"</code>)</td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","messages","email"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"a5af8cae-2d2e-fe43-bc15-5851a814f5f7"},{"name":"⚠ Update a message row","id":"793babf8-3056-c9f7-1611-79b093c4bf7a","request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"expectedRevision\": {{messageRevision}},\n  \"changes\": { \"custom2\": \"checked\", \"metadata\": { \"note\": \"synthetic\" } }\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/messages/email/{{messageId}}/update","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/messages/email/{{messageId}}/update</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Changes optional fields at the revision you read. <code>status</code> moves only along the allowed transitions (pending→cancelled, sent→delivered/read/failed, delivered→read, failed→cancelled); <code>companyCode</code> and <code>idempotencyKey</code> never change; recorded evidence (<code>providerMessageId</code>, <code>sentUtc</code>, <code>deliveredUtc</code>, <code>readUtc</code>) is never replaced by a different value.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the row</td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>MESSAGE_INVALID</code></td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>MESSAGE_NOT_FOUND</code></td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>MESSAGE_CONFLICT</code>, <code>MESSAGE_CLAIMED</code>, <code>MESSAGE_TRANSITION_INVALID</code>, <code>MESSAGE_EVIDENCE_CONFLICT</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","messages","email","{{messageId}}","update"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"793babf8-3056-c9f7-1611-79b093c4bf7a"},{"name":"⚠ Reconcile an uncertain message","id":"69fcc35c-ac4e-1bc5-60a6-c02bf96cbd70","request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"expectedRevision\": {{messageRevision}},\n  \"outcome\": \"failed\",\n  \"note\": \"Checked the provider: not accepted.\",\n  \"errorCode\": \"NOT_ACCEPTED\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/messages/email/{{messageId}}/reconcile","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/messages/email/{{messageId}}/reconcile</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Records what really happened to an <code>uncertain</code> row after checking with the provider: <code>sent</code>, <code>delivered</code>, <code>failed</code>, <code>cancelled</code>, or <code>pending</code> (send again — needs <code>\"acknowledgeDuplicateRisk\": true</code>, the recipient may get it twice). Also cancels a <code>pending</code> or <code>failed</code> row. Optional <code>note</code>, <code>providerMessageId</code> (sent / delivered), <code>errorCode</code>, <code>errorMessage</code>. AI Zeny contacts no provider.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td>the row</td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>MESSAGE_INVALID</code> with <code>field</code></td>\n</tr>\n<tr>\n<td>404</td>\n<td><code>MESSAGE_NOT_FOUND</code></td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>MESSAGE_CONFLICT</code> (revision moved), <code>MESSAGE_TRANSITION_INVALID</code> (e.g. <code>pending</code> without the acknowledgement: <code>field: acknowledgeDuplicateRisk</code>)</td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","messages","email","{{messageId}}","reconcile"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"69fcc35c-ac4e-1bc5-60a6-c02bf96cbd70"},{"name":"⚠ Delete message rows (permanent)","id":"e3845d19-aa98-ae4a-b50d-4347e568d77e","request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\n  \"ids\": [{{messageId}}],\n  \"confirm\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/messages/email/delete","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/messages/email/delete</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · <strong>Changes AI Zeny on the PC</strong> (not BUSY; guarded by <code>confirmMutating</code>)\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — run manually. Permanent.</strong> Deletes 1-500 rows with their attempts and events, for removing test rows. <code>confirm: true</code> is required; rows in <code>processing</code> are refused. AI Zeny never deletes history by itself.</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Status</th>\n<th>Body</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>200</td>\n<td><code>{ deleted }</code></td>\n</tr>\n<tr>\n<td>400</td>\n<td><code>MESSAGE_INVALID</code> (<code>confirm</code>, <code>ids</code>)</td>\n</tr>\n<tr>\n<td>409</td>\n<td><code>MESSAGE_CLAIMED</code></td>\n</tr>\n</tbody>\n</table>\n</div><p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","messages","email","delete"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"e3845d19-aa98-ae4a-b50d-4347e568d77e"}],"id":"2dc22940-536c-4d73-bdc6-f26dbd68156b","description":"<p>Guarded by <code>confirmMutating</code>; changes AI Zeny on the PC, not BUSY. Part of ⚠ PC Settings &amp; Management.</p>\n","_postman_id":"2dc22940-536c-4d73-bdc6-f26dbd68156b","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ Report PDFs — native side effects unverified","item":[{"name":"⚠ busy.reports.account-ledger.pdf – Account Ledger PDF","id":"e4de3478-189c-0f65-6fb9-c24c46a4deeb","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": {{customerId}} },\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-06-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-ledger-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /api/v1/account-ledger-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.</p>\n<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/account-ledger-pdf</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · ⚠ Native report-PDF side effects unverified\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>account</code> · operation <code>busy.reports.account-ledger.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<p><strong>Status (2026-10-16):</strong> implemented and accepted for the Windows / Local API scope; installed service-account acceptance passed 2026-10-16 (COMP0002 / FY 2026, values recalculated on the day, no table changed). Public builds up to 0.0.12 do not have the route and answer <code>404</code>. Re-checked by the 2026-10-18 Local API acceptance audit on the installed 0.0.14.</p>\n<hr />\n<p><strong><code>busy.reports.account-ledger.pdf</code></strong> (<code>POST /api/v1/account-ledger-pdf</code>). One account's <strong>Account Ledger</strong> printed by <strong>BUSY's own report printing</strong> (BUSY report 19) on this PC and returned as a PDF in <code>data.contentBase64</code> (standard base64, one line). BUSY prints the opening balance at <code>fromDate</code>, every entry of the period with its running balance, the totals and the closing balance, in its own built-in layout with its background mark.</p>\n<p><strong>Variables:</strong> the body uses <code>{{customerId}}</code> (an account of <code>{{companyCode}}</code>; COMP0002 = 1289) and the first quarter of <code>{{financialYear}}</code> (<code>{{financialYear}}-04-01</code> to <code>{{financialYear}}-06-30</code>), so changing the year keeps the dates inside it. Remove both dates for the whole year, or send <code>{\"name\": \"…\"}</code> instead of the code.</p>\n<p>Request: <code>{ companyCode, financialYear, account, fromDate?, toDate? }</code></p>\n<ul>\n<li><code>account</code>: exactly one of <code>{\"code\": n}</code> or <code>{\"name\": \"…\"}</code> (compared without case and surrounding spaces; an alias is not accepted). An <strong>account</strong> master only: a group's or item's code is <code>404 NOT_FOUND</code>. <code>422 MASTER_REFERENCE_AMBIGUOUS</code> when several accounts share the name or another account holds it as its alias (BUSY's report finds its account by name or alias).</li>\n<li><code>fromDate</code>, <code>toDate</code>: optional <code>YYYY-MM-DD</code>, real dates <strong>inside the selected financial year</strong>, <code>fromDate</code> ≤ <code>toDate</code>; default the whole year. Anything else is <code>400 INVALID_PARAMETER</code> — BUSY itself would print a wrong report.</li>\n<li>No <code>formatName</code>, ageing, sorting, narration or column options exist (unknown members <code>400 BAD_REQUEST</code>).</li>\n</ul>\n<p>Response (200): <code>data</code> = <code>{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }</code>, <code>fileName</code> <code>AccountLedger-&lt;company&gt;-&lt;year&gt;-&lt;code&gt;-&lt;from&gt;-&lt;to&gt;.pdf</code>. <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, report (\"accountLedger\"), busyReportId (19), account {code, name}, fromDate, toDate, elapsedMs, executedAt</code>.</p>\n<p>Errors: <code>400 INVALID_PARAMETER</code> / <code>BAD_REQUEST</code>; <code>404 NOT_FOUND</code>; <code>409 BUSY_REPORT_PROVIDER_UNSUPPORTED</code> (Access), <code>BUSY_REPORT_ACCOUNT_CHANGED</code>, <code>BUSY_COM_SIGN_IN_UNSUPPORTED</code>; <code>422 MASTER_REFERENCE_AMBIGUOUS</code>, <code>BUSY_DATA_INCONSISTENT</code>, <code>RESULT_TOO_LARGE</code> (over 8 MiB, never cut), <code>BUSY_COM_PDF_BLANK</code>; <code>502 BUSY_COM_*</code> print failures; <code>503</code> prerequisites and <code>BUSY_COM_QUEUE_TIMEOUT</code>; <code>504 BUSY_COM_TIMEOUT</code>. SQL Server companies only. One BUSY job at a time, up to 2 minutes: give the request a long timeout. Inspect the outcome and reconfirm before any repeat.</p>\n<p>Cloud: no cloud route exists (Local API only).</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5aj; <code>docs/features/BUSY-Report-PDF-API.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","account-ledger-pdf"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"6f75a03c-e781-b1e1-5eff-9befa8099011","name":"200 – Account Ledger PDF (synthetic example)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": {{customerId}} },\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-06-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-ledger-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/account-ledger-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Local** · `POST {{baseUrl}}/api/v1/account-ledger-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ Native report-PDF side effects unverified\n**Required:** `companyCode`, `financialYear`, `account` · operation `busy.reports.account-ledger.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Status (2026-10-16):** implemented and accepted for the Windows / Local API scope; installed service-account acceptance passed 2026-10-16 (COMP0002 / FY 2026, values recalculated on the day, no table changed). Public builds up to 0.0.12 do not have the route and answer `404`. Re-checked by the 2026-10-18 Local API acceptance audit on the installed 0.0.14.\n\n---\n\n**`busy.reports.account-ledger.pdf`** (`POST /api/v1/account-ledger-pdf`). One account's **Account Ledger** printed by **BUSY's own report printing** (BUSY report 19) on this PC and returned as a PDF in `data.contentBase64` (standard base64, one line). BUSY prints the opening balance at `fromDate`, every entry of the period with its running balance, the totals and the closing balance, in its own built-in layout with its background mark.\n\n**Variables:** the body uses `{{customerId}}` (an account of `{{companyCode}}`; COMP0002 = 1289) and the first quarter of `{{financialYear}}` (`{{financialYear}}-04-01` to `{{financialYear}}-06-30`), so changing the year keeps the dates inside it. Remove both dates for the whole year, or send `{\"name\": \"…\"}` instead of the code.\n\nRequest: `{ companyCode, financialYear, account, fromDate?, toDate? }`\n- `account`: exactly one of `{\"code\": n}` or `{\"name\": \"…\"}` (compared without case and surrounding spaces; an alias is not accepted). An **account** master only: a group's or item's code is `404 NOT_FOUND`. `422 MASTER_REFERENCE_AMBIGUOUS` when several accounts share the name or another account holds it as its alias (BUSY's report finds its account by name or alias).\n- `fromDate`, `toDate`: optional `YYYY-MM-DD`, real dates **inside the selected financial year**, `fromDate` ≤ `toDate`; default the whole year. Anything else is `400 INVALID_PARAMETER` — BUSY itself would print a wrong report.\n- No `formatName`, ageing, sorting, narration or column options exist (unknown members `400 BAD_REQUEST`).\n\nResponse (200): `data` = `{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }`, `fileName` `AccountLedger-<company>-<year>-<code>-<from>-<to>.pdf`. `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"accountLedger\"), busyReportId (19), account {code, name}, fromDate, toDate, elapsedMs, executedAt`.\n\nErrors: `400 INVALID_PARAMETER` / `BAD_REQUEST`; `404 NOT_FOUND`; `409 BUSY_REPORT_PROVIDER_UNSUPPORTED` (Access), `BUSY_REPORT_ACCOUNT_CHANGED`, `BUSY_COM_SIGN_IN_UNSUPPORTED`; `422 MASTER_REFERENCE_AMBIGUOUS`, `BUSY_DATA_INCONSISTENT`, `RESULT_TOO_LARGE` (over 8 MiB, never cut), `BUSY_COM_PDF_BLANK`; `502 BUSY_COM_*` print failures; `503` prerequisites and `BUSY_COM_QUEUE_TIMEOUT`; `504 BUSY_COM_TIMEOUT`. SQL Server companies only. One BUSY job at a time, up to 2 minutes: give the request a long timeout. Inspect the outcome and reconfirm before any repeat.\n\nCloud: no cloud route exists (Local API only).\n\nCanonical contract: `docs/LOCAL-API.md` section 5aj; `docs/features/BUSY-Report-PDF-API.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e20","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"fileName\": \"AccountLedger-COMP0002-2026-7101-2026-04-01-2026-06-30.pdf\",\n    \"mimeType\": \"application/pdf\",\n    \"byteLength\": 54,\n    \"sha256\": \"489ffb43555619d787dcc6b7d2117d4a061970f975a531e413b8b4f74f4ca303\",\n    \"pages\": 1,\n    \"contentBase64\": \"JVBERi0xLjQKJSBzeW50aGV0aWMgZXhhbXBsZSwgbm90IGEgcmVhbCByZXBvcnQKJSVFT0YK\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.reports.account-ledger.pdf\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e20\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"report\": \"accountLedger\",\n    \"busyReportId\": 19,\n    \"account\": { \"code\": 7101, \"name\": \"Synthetic Traders\" },\n    \"fromDate\": \"2026-04-01\",\n    \"toDate\": \"2026-06-30\",\n    \"elapsedMs\": 4180,\n    \"executedAt\": \"2026-10-16T10:00:00+00:00\"\n  }\n}"},{"id":"7e50009a-c0ba-c42b-22ea-5192c3e306a0","name":"400 – a date outside the financial year","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": {{customerId}} },\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-06-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/account-ledger-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/account-ledger-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Local** · `POST {{baseUrl}}/api/v1/account-ledger-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ Native report-PDF side effects unverified\n**Required:** `companyCode`, `financialYear`, `account` · operation `busy.reports.account-ledger.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Status (2026-10-16):** implemented and accepted for the Windows / Local API scope; installed service-account acceptance passed 2026-10-16 (COMP0002 / FY 2026, values recalculated on the day, no table changed). Public builds up to 0.0.12 do not have the route and answer `404`. Re-checked by the 2026-10-18 Local API acceptance audit on the installed 0.0.14.\n\n---\n\n**`busy.reports.account-ledger.pdf`** (`POST /api/v1/account-ledger-pdf`). One account's **Account Ledger** printed by **BUSY's own report printing** (BUSY report 19) on this PC and returned as a PDF in `data.contentBase64` (standard base64, one line). BUSY prints the opening balance at `fromDate`, every entry of the period with its running balance, the totals and the closing balance, in its own built-in layout with its background mark.\n\n**Variables:** the body uses `{{customerId}}` (an account of `{{companyCode}}`; COMP0002 = 1289) and the first quarter of `{{financialYear}}` (`{{financialYear}}-04-01` to `{{financialYear}}-06-30`), so changing the year keeps the dates inside it. Remove both dates for the whole year, or send `{\"name\": \"…\"}` instead of the code.\n\nRequest: `{ companyCode, financialYear, account, fromDate?, toDate? }`\n- `account`: exactly one of `{\"code\": n}` or `{\"name\": \"…\"}` (compared without case and surrounding spaces; an alias is not accepted). An **account** master only: a group's or item's code is `404 NOT_FOUND`. `422 MASTER_REFERENCE_AMBIGUOUS` when several accounts share the name or another account holds it as its alias (BUSY's report finds its account by name or alias).\n- `fromDate`, `toDate`: optional `YYYY-MM-DD`, real dates **inside the selected financial year**, `fromDate` ≤ `toDate`; default the whole year. Anything else is `400 INVALID_PARAMETER` — BUSY itself would print a wrong report.\n- No `formatName`, ageing, sorting, narration or column options exist (unknown members `400 BAD_REQUEST`).\n\nResponse (200): `data` = `{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }`, `fileName` `AccountLedger-<company>-<year>-<code>-<from>-<to>.pdf`. `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"accountLedger\"), busyReportId (19), account {code, name}, fromDate, toDate, elapsedMs, executedAt`.\n\nErrors: `400 INVALID_PARAMETER` / `BAD_REQUEST`; `404 NOT_FOUND`; `409 BUSY_REPORT_PROVIDER_UNSUPPORTED` (Access), `BUSY_REPORT_ACCOUNT_CHANGED`, `BUSY_COM_SIGN_IN_UNSUPPORTED`; `422 MASTER_REFERENCE_AMBIGUOUS`, `BUSY_DATA_INCONSISTENT`, `RESULT_TOO_LARGE` (over 8 MiB, never cut), `BUSY_COM_PDF_BLANK`; `502 BUSY_COM_*` print failures; `503` prerequisites and `BUSY_COM_QUEUE_TIMEOUT`; `504 BUSY_COM_TIMEOUT`. SQL Server companies only. One BUSY job at a time, up to 2 minutes: give the request a long timeout. Inspect the outcome and reconfirm before any repeat.\n\nCloud: no cloud route exists (Local API only).\n\nCanonical contract: `docs/LOCAL-API.md` section 5aj; `docs/features/BUSY-Report-PDF-API.md`."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e21"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"toDate must be inside the selected financial year (2026-04-01 to 2027-03-31).\",\n      \"field\": \"toDate\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e21\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"e4de3478-189c-0f65-6fb9-c24c46a4deeb"},{"name":"⚠ busy.reports.bills-receivable.pdf – Bills Receivable PDF","id":"892039dc-0f40-fa52-d5ce-564efb36debd","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": {{customerId}} },\n  \"status\": \"pending\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/bills-receivable-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /api/v1/bills-receivable-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.</p>\n<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/bills-receivable-pdf</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · ⚠ Native report-PDF side effects unverified\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>account</code> · operation <code>busy.reports.bills-receivable.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<p><strong>Status (2026-10-16):</strong> implemented and accepted for the Windows / Local API scope; installed service-account acceptance passed 2026-10-16 (COMP0002 / FY 2026, values recalculated on the day, no table changed). Public builds up to 0.0.12 do not have the route and answer <code>404</code>. Re-checked by the 2026-10-18 Local API acceptance audit on the installed 0.0.14.</p>\n<hr />\n<p><strong><code>busy.reports.bills-receivable.pdf</code></strong> (<code>POST /api/v1/bills-receivable-pdf</code>). One account's <strong>Bills Receivable</strong> (bill-by-bill outstanding) report printed by <strong>BUSY's own report printing</strong> (BUSY report 201, receivable side) on this PC and returned as a PDF in <code>data.contentBase64</code> (standard base64, one line). Receivable bill references only: advances and other credit references and on-account amounts are not in it.</p>\n<p><strong>Variables:</strong> the body uses <code>{{customerId}}</code>, which must be an account of <code>{{companyCode}}</code> that BUSY keeps <strong>bill by bill</strong> (COMP0002 = 1289). Or send <code>{\"name\": \"…\"}</code> instead of the code.</p>\n<p>Request: <code>{ companyCode, financialYear, account, asOfDate?, status? }</code></p>\n<ul>\n<li><code>account</code>: as for the Account Ledger PDF; the account must be kept bill by bill, else <code>422 REPORT_ACCOUNT_NOT_BILL_BY_BILL</code>.</li>\n<li><code>asOfDate</code>: optional <code>YYYY-MM-DD</code> inside the selected financial year (the \"status as on\" date). Default: today in India, kept inside the year (its last day for a past year, its first day for a year not yet begun).</li>\n<li><code>status</code>: optional, exact: <code>pending</code> (default; outstanding bills), <code>overdue</code> (outstanding and due on or before <code>asOfDate</code>), <code>all</code> (settled bills included with pending 0).</li>\n<li>Not offered here: the payable side (its own route, <code>POST /api/v1/bills-payable-pdf</code>), all accounts at once, BUSY's start date, format, ageing, sorting or column options (unknown members <code>400 BAD_REQUEST</code>).</li>\n</ul>\n<p>Response (200): <code>data</code> = <code>{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }</code>, <code>fileName</code> <code>BillsReceivable-&lt;company&gt;-&lt;year&gt;-&lt;code&gt;-&lt;asOf&gt;-&lt;status&gt;.pdf</code>. <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, report (\"billsReceivable\"), busyReportId (201), account {code, name}, asOfDate, status, elapsedMs, executedAt</code>.</p>\n<p>Errors: as the Account Ledger PDF, plus <code>422 REPORT_ACCOUNT_NOT_BILL_BY_BILL</code>. SQL Server companies only. One BUSY job at a time, up to 2 minutes: give the request a long timeout. Inspect the outcome and reconfirm before any repeat.</p>\n<p>Cloud: no cloud route exists (Local API only).</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5aj; <code>docs/features/BUSY-Report-PDF-API.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","bills-receivable-pdf"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"6530aaeb-852c-39e7-558a-d4f74c0d136f","name":"200 – Bills Receivable PDF, overdue (synthetic example)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": {{customerId}} },\n  \"status\": \"pending\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/bills-receivable-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/bills-receivable-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Local** · `POST {{baseUrl}}/api/v1/bills-receivable-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ Native report-PDF side effects unverified\n**Required:** `companyCode`, `financialYear`, `account` · operation `busy.reports.bills-receivable.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Status (2026-10-16):** implemented and accepted for the Windows / Local API scope; installed service-account acceptance passed 2026-10-16 (COMP0002 / FY 2026, values recalculated on the day, no table changed). Public builds up to 0.0.12 do not have the route and answer `404`. Re-checked by the 2026-10-18 Local API acceptance audit on the installed 0.0.14.\n\n---\n\n**`busy.reports.bills-receivable.pdf`** (`POST /api/v1/bills-receivable-pdf`). One account's **Bills Receivable** (bill-by-bill outstanding) report printed by **BUSY's own report printing** (BUSY report 201, receivable side) on this PC and returned as a PDF in `data.contentBase64` (standard base64, one line). Receivable bill references only: advances and other credit references and on-account amounts are not in it.\n\n**Variables:** the body uses `{{customerId}}`, which must be an account of `{{companyCode}}` that BUSY keeps **bill by bill** (COMP0002 = 1289). Or send `{\"name\": \"…\"}` instead of the code.\n\nRequest: `{ companyCode, financialYear, account, asOfDate?, status? }`\n- `account`: as for the Account Ledger PDF; the account must be kept bill by bill, else `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`.\n- `asOfDate`: optional `YYYY-MM-DD` inside the selected financial year (the \"status as on\" date). Default: today in India, kept inside the year (its last day for a past year, its first day for a year not yet begun).\n- `status`: optional, exact: `pending` (default; outstanding bills), `overdue` (outstanding and due on or before `asOfDate`), `all` (settled bills included with pending 0).\n- Not offered here: the payable side (its own route, `POST /api/v1/bills-payable-pdf`), all accounts at once, BUSY's start date, format, ageing, sorting or column options (unknown members `400 BAD_REQUEST`).\n\nResponse (200): `data` = `{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }`, `fileName` `BillsReceivable-<company>-<year>-<code>-<asOf>-<status>.pdf`. `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"billsReceivable\"), busyReportId (201), account {code, name}, asOfDate, status, elapsedMs, executedAt`.\n\nErrors: as the Account Ledger PDF, plus `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`. SQL Server companies only. One BUSY job at a time, up to 2 minutes: give the request a long timeout. Inspect the outcome and reconfirm before any repeat.\n\nCloud: no cloud route exists (Local API only).\n\nCanonical contract: `docs/LOCAL-API.md` section 5aj; `docs/features/BUSY-Report-PDF-API.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e22","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"fileName\": \"BillsReceivable-COMP0002-2026-7101-2026-09-30-overdue.pdf\",\n    \"mimeType\": \"application/pdf\",\n    \"byteLength\": 54,\n    \"sha256\": \"489ffb43555619d787dcc6b7d2117d4a061970f975a531e413b8b4f74f4ca303\",\n    \"pages\": 1,\n    \"contentBase64\": \"JVBERi0xLjQKJSBzeW50aGV0aWMgZXhhbXBsZSwgbm90IGEgcmVhbCByZXBvcnQKJSVFT0YK\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.reports.bills-receivable.pdf\",\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e22\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"report\": \"billsReceivable\",\n    \"busyReportId\": 201,\n    \"account\": { \"code\": 7101, \"name\": \"Synthetic Traders\" },\n    \"asOfDate\": \"2026-09-30\",\n    \"status\": \"overdue\",\n    \"elapsedMs\": 3960,\n    \"executedAt\": \"2026-10-16T10:00:00+00:00\"\n  }\n}"},{"id":"b8eff271-707f-34cb-7319-fea257cdd6ab","name":"422 – account not kept bill by bill","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": {{customerId}} },\n  \"status\": \"pending\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/bills-receivable-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/bills-receivable-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Local** · `POST {{baseUrl}}/api/v1/bills-receivable-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ Native report-PDF side effects unverified\n**Required:** `companyCode`, `financialYear`, `account` · operation `busy.reports.bills-receivable.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Status (2026-10-16):** implemented and accepted for the Windows / Local API scope; installed service-account acceptance passed 2026-10-16 (COMP0002 / FY 2026, values recalculated on the day, no table changed). Public builds up to 0.0.12 do not have the route and answer `404`. Re-checked by the 2026-10-18 Local API acceptance audit on the installed 0.0.14.\n\n---\n\n**`busy.reports.bills-receivable.pdf`** (`POST /api/v1/bills-receivable-pdf`). One account's **Bills Receivable** (bill-by-bill outstanding) report printed by **BUSY's own report printing** (BUSY report 201, receivable side) on this PC and returned as a PDF in `data.contentBase64` (standard base64, one line). Receivable bill references only: advances and other credit references and on-account amounts are not in it.\n\n**Variables:** the body uses `{{customerId}}`, which must be an account of `{{companyCode}}` that BUSY keeps **bill by bill** (COMP0002 = 1289). Or send `{\"name\": \"…\"}` instead of the code.\n\nRequest: `{ companyCode, financialYear, account, asOfDate?, status? }`\n- `account`: as for the Account Ledger PDF; the account must be kept bill by bill, else `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`.\n- `asOfDate`: optional `YYYY-MM-DD` inside the selected financial year (the \"status as on\" date). Default: today in India, kept inside the year (its last day for a past year, its first day for a year not yet begun).\n- `status`: optional, exact: `pending` (default; outstanding bills), `overdue` (outstanding and due on or before `asOfDate`), `all` (settled bills included with pending 0).\n- Not offered here: the payable side (its own route, `POST /api/v1/bills-payable-pdf`), all accounts at once, BUSY's start date, format, ageing, sorting or column options (unknown members `400 BAD_REQUEST`).\n\nResponse (200): `data` = `{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }`, `fileName` `BillsReceivable-<company>-<year>-<code>-<asOf>-<status>.pdf`. `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"billsReceivable\"), busyReportId (201), account {code, name}, asOfDate, status, elapsedMs, executedAt`.\n\nErrors: as the Account Ledger PDF, plus `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`. SQL Server companies only. One BUSY job at a time, up to 2 minutes: give the request a long timeout. Inspect the outcome and reconfirm before any repeat.\n\nCloud: no cloud route exists (Local API only).\n\nCanonical contract: `docs/LOCAL-API.md` section 5aj; `docs/features/BUSY-Report-PDF-API.md`."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e23"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"REPORT_ACCOUNT_NOT_BILL_BY_BILL\",\n      \"message\": \"BUSY does not keep this account bill by bill, so it has no bill-wise receivables. Use the Account Ledger PDF for it.\",\n      \"field\": \"account\"\n    },\n    \"requestId\": \"5f0c2a9e7d3b4c1a8e6f0b2d4c6a8e23\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"892039dc-0f40-fa52-d5ce-564efb36debd"},{"name":"⚠ busy.reports.payment-reminder.pdf – Payment Reminder PDF","id":"3d6ef4ae-257d-f98e-e1e8-c9b6adf6c7e3","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": {{customerId}} },\n  \"bills\": \"pending\",\n  \"itemDetails\": false,\n  \"boldDueBills\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/payment-reminder-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /api/v1/payment-reminder-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.</p>\n<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/payment-reminder-pdf</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · ⚠ Native report-PDF side effects unverified\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>account</code> · operation <code>busy.reports.payment-reminder.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<p><strong>Status (2026-10-16):</strong> implemented and accepted for the Windows / Local API scope (the Payment Reminder PoC was accepted for one account); installed service-account acceptance passed 2026-10-16 (COMP0002 / FY 2026, values recalculated on the day, no table changed). Public builds up to 0.0.12 do not have the route and answer <code>404</code>. Re-checked by the 2026-10-18 Local API acceptance audit on the installed 0.0.14.</p>\n<hr />\n<p><strong><code>busy.reports.payment-reminder.pdf</code></strong> (<code>POST /api/v1/payment-reminder-pdf</code>). One customer's <strong>Payment Reminder</strong> letter printed by <strong>BUSY's own report printing</strong> (BUSY report 150) on this PC and returned as a PDF in <code>data.contentBase64</code> (standard base64, one line): To the customer, From the company, the balance of its pending (or due) bills as on a date, and the bill list with a grand total.</p>\n<p><strong>Variables:</strong> the body uses <code>{{customerId}}</code>, which must be an account of <code>{{companyCode}}</code> that BUSY keeps <strong>bill by bill</strong> (COMP0002 = 1289). Or send <code>{\"name\": \"…\"}</code> instead of the code.</p>\n<p>Request: <code>{ companyCode, financialYear, account, asOfDate?, bills?, formatName?, itemDetails?, boldDueBills? }</code></p>\n<ul>\n<li><code>account</code>: <code>{code}</code> or <code>{name}</code> (an account master, not an alias), kept bill by bill, else <code>422 REPORT_ACCOUNT_NOT_BILL_BY_BILL</code>.</li>\n<li><code>asOfDate</code>: optional <code>YYYY-MM-DD</code> inside the selected financial year. Default: today in India, kept inside the year.</li>\n<li><code>bills</code>: optional, exact: <code>pending</code> (default; every outstanding bill) or <code>due</code> (outstanding and due on or before <code>asOfDate</code>).</li>\n<li><code>formatName</code>: optional, one of the company's Payment Reminder formats in BUSY, exactly as named (case-sensitive), 1-64 characters. Absent = <code>STANDARD</code>. An unknown name is <code>404 NOT_FOUND</code> (<code>field: formatName</code>, the message lists the company's formats); without <code>formatName</code> and without a <code>STANDARD</code> format <code>409 BUSY_PRINT_FORMAT_MISSING</code>. A format is never created and never replaced by another.</li>\n<li><code>itemDetails</code>: optional Boolean, default <code>false</code> (item lines under each invoice). <code>boldDueBills</code>: optional Boolean, default <code>true</code>.</li>\n<li>Not offered: a group, several or all accounts, branch, series or optional-field filters, other BUSY switches (unknown members <code>400 BAD_REQUEST</code>).</li>\n</ul>\n<p>Response (200): <code>data</code> = <code>{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }</code>, <code>fileName</code> <code>PaymentReminder-&lt;company&gt;-&lt;year&gt;-&lt;code&gt;-&lt;asOf&gt;-&lt;bills&gt;.pdf</code>. <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, report (\"paymentReminder\"), busyReportId (150), account {code, name}, asOfDate, bills, formatSource (\"default\" | \"selected\"), formatName, itemDetails, boldDueBills, elapsedMs, executedAt</code>.</p>\n<p>Errors: as the Account Ledger PDF, plus the format errors above and <code>422 REPORT_ACCOUNT_NOT_BILL_BY_BILL</code>. SQL Server companies only. One BUSY job at a time, up to 2 minutes: give the request a long timeout. Inspect the outcome and reconfirm before any repeat. At most 8 MiB (<code>422 RESULT_TOO_LARGE</code>, never cut).</p>\n<p>Upgrade note: BUSY reads 25 positions for this report on the installed BUSY version, 8 of them undocumented (sent empty); re-check after a BUSY upgrade.</p>\n<p>Cloud: no cloud route exists (Local API only).</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5ak; <code>docs/features/BUSY-Report-PDF-2-API.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","payment-reminder-pdf"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"1dfb1984-5480-fa3c-9c3e-54ea7d1d2d07","name":"200 – pending bills, STANDARD format (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": {{customerId}} },\n  \"bills\": \"pending\",\n  \"itemDetails\": false,\n  \"boldDueBills\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/payment-reminder-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/payment-reminder-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Local** · `POST {{baseUrl}}/api/v1/payment-reminder-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ Native report-PDF side effects unverified\n**Required:** `companyCode`, `financialYear`, `account` · operation `busy.reports.payment-reminder.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Status (2026-10-16):** implemented and accepted for the Windows / Local API scope (the Payment Reminder PoC was accepted for one account); installed service-account acceptance passed 2026-10-16 (COMP0002 / FY 2026, values recalculated on the day, no table changed). Public builds up to 0.0.12 do not have the route and answer `404`. Re-checked by the 2026-10-18 Local API acceptance audit on the installed 0.0.14.\n\n---\n\n**`busy.reports.payment-reminder.pdf`** (`POST /api/v1/payment-reminder-pdf`). One customer's **Payment Reminder** letter printed by **BUSY's own report printing** (BUSY report 150) on this PC and returned as a PDF in `data.contentBase64` (standard base64, one line): To the customer, From the company, the balance of its pending (or due) bills as on a date, and the bill list with a grand total.\n\n**Variables:** the body uses `{{customerId}}`, which must be an account of `{{companyCode}}` that BUSY keeps **bill by bill** (COMP0002 = 1289). Or send `{\"name\": \"…\"}` instead of the code.\n\nRequest: `{ companyCode, financialYear, account, asOfDate?, bills?, formatName?, itemDetails?, boldDueBills? }`\n- `account`: `{code}` or `{name}` (an account master, not an alias), kept bill by bill, else `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`.\n- `asOfDate`: optional `YYYY-MM-DD` inside the selected financial year. Default: today in India, kept inside the year.\n- `bills`: optional, exact: `pending` (default; every outstanding bill) or `due` (outstanding and due on or before `asOfDate`).\n- `formatName`: optional, one of the company's Payment Reminder formats in BUSY, exactly as named (case-sensitive), 1-64 characters. Absent = `STANDARD`. An unknown name is `404 NOT_FOUND` (`field: formatName`, the message lists the company's formats); without `formatName` and without a `STANDARD` format `409 BUSY_PRINT_FORMAT_MISSING`. A format is never created and never replaced by another.\n- `itemDetails`: optional Boolean, default `false` (item lines under each invoice). `boldDueBills`: optional Boolean, default `true`.\n- Not offered: a group, several or all accounts, branch, series or optional-field filters, other BUSY switches (unknown members `400 BAD_REQUEST`).\n\nResponse (200): `data` = `{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }`, `fileName` `PaymentReminder-<company>-<year>-<code>-<asOf>-<bills>.pdf`. `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"paymentReminder\"), busyReportId (150), account {code, name}, asOfDate, bills, formatSource (\"default\" | \"selected\"), formatName, itemDetails, boldDueBills, elapsedMs, executedAt`.\n\nErrors: as the Account Ledger PDF, plus the format errors above and `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`. SQL Server companies only. One BUSY job at a time, up to 2 minutes: give the request a long timeout. Inspect the outcome and reconfirm before any repeat. At most 8 MiB (`422 RESULT_TOO_LARGE`, never cut).\n\nUpgrade note: BUSY reads 25 positions for this report on the installed BUSY version, 8 of them undocumented (sent empty); re-check after a BUSY upgrade.\n\nCloud: no cloud route exists (Local API only).\n\nCanonical contract: `docs/LOCAL-API.md` section 5ak; `docs/features/BUSY-Report-PDF-2-API.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"7a1c3e5f9b2d4f6a8c0e2a4c6e8a0c41","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"fileName\": \"PaymentReminder-COMP0002-2026-7101-2026-10-16-pending.pdf\",\n    \"mimeType\": \"application/pdf\",\n    \"byteLength\": 54,\n    \"sha256\": \"489ffb43555619d787dcc6b7d2117d4a061970f975a531e413b8b4f74f4ca303\",\n    \"pages\": 1,\n    \"contentBase64\": \"JVBERi0xLjQKJSBzeW50aGV0aWMgZXhhbXBsZSwgbm90IGEgcmVhbCByZXBvcnQKJSVFT0YK\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.reports.payment-reminder.pdf\",\n    \"requestId\": \"7a1c3e5f9b2d4f6a8c0e2a4c6e8a0c41\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"report\": \"paymentReminder\",\n    \"busyReportId\": 150,\n    \"account\": { \"code\": 7101, \"name\": \"Synthetic Traders\" },\n    \"asOfDate\": \"2026-10-16\",\n    \"bills\": \"pending\",\n    \"formatSource\": \"default\",\n    \"formatName\": \"STANDARD\",\n    \"itemDetails\": false,\n    \"boldDueBills\": true,\n    \"elapsedMs\": 4210,\n    \"executedAt\": \"2026-10-16T07:30:00.0000000Z\"\n  }\n}"},{"id":"d6997eb3-d6b5-3242-dcae-3036cf4b8431","name":"404 – formatName not a Payment Reminder format of the company","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": {{customerId}} },\n  \"bills\": \"pending\",\n  \"itemDetails\": false,\n  \"boldDueBills\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/payment-reminder-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/payment-reminder-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Local** · `POST {{baseUrl}}/api/v1/payment-reminder-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ Native report-PDF side effects unverified\n**Required:** `companyCode`, `financialYear`, `account` · operation `busy.reports.payment-reminder.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Status (2026-10-16):** implemented and accepted for the Windows / Local API scope (the Payment Reminder PoC was accepted for one account); installed service-account acceptance passed 2026-10-16 (COMP0002 / FY 2026, values recalculated on the day, no table changed). Public builds up to 0.0.12 do not have the route and answer `404`. Re-checked by the 2026-10-18 Local API acceptance audit on the installed 0.0.14.\n\n---\n\n**`busy.reports.payment-reminder.pdf`** (`POST /api/v1/payment-reminder-pdf`). One customer's **Payment Reminder** letter printed by **BUSY's own report printing** (BUSY report 150) on this PC and returned as a PDF in `data.contentBase64` (standard base64, one line): To the customer, From the company, the balance of its pending (or due) bills as on a date, and the bill list with a grand total.\n\n**Variables:** the body uses `{{customerId}}`, which must be an account of `{{companyCode}}` that BUSY keeps **bill by bill** (COMP0002 = 1289). Or send `{\"name\": \"…\"}` instead of the code.\n\nRequest: `{ companyCode, financialYear, account, asOfDate?, bills?, formatName?, itemDetails?, boldDueBills? }`\n- `account`: `{code}` or `{name}` (an account master, not an alias), kept bill by bill, else `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`.\n- `asOfDate`: optional `YYYY-MM-DD` inside the selected financial year. Default: today in India, kept inside the year.\n- `bills`: optional, exact: `pending` (default; every outstanding bill) or `due` (outstanding and due on or before `asOfDate`).\n- `formatName`: optional, one of the company's Payment Reminder formats in BUSY, exactly as named (case-sensitive), 1-64 characters. Absent = `STANDARD`. An unknown name is `404 NOT_FOUND` (`field: formatName`, the message lists the company's formats); without `formatName` and without a `STANDARD` format `409 BUSY_PRINT_FORMAT_MISSING`. A format is never created and never replaced by another.\n- `itemDetails`: optional Boolean, default `false` (item lines under each invoice). `boldDueBills`: optional Boolean, default `true`.\n- Not offered: a group, several or all accounts, branch, series or optional-field filters, other BUSY switches (unknown members `400 BAD_REQUEST`).\n\nResponse (200): `data` = `{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }`, `fileName` `PaymentReminder-<company>-<year>-<code>-<asOf>-<bills>.pdf`. `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"paymentReminder\"), busyReportId (150), account {code, name}, asOfDate, bills, formatSource (\"default\" | \"selected\"), formatName, itemDetails, boldDueBills, elapsedMs, executedAt`.\n\nErrors: as the Account Ledger PDF, plus the format errors above and `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`. SQL Server companies only. One BUSY job at a time, up to 2 minutes: give the request a long timeout. Inspect the outcome and reconfirm before any repeat. At most 8 MiB (`422 RESULT_TOO_LARGE`, never cut).\n\nUpgrade note: BUSY reads 25 positions for this report on the installed BUSY version, 8 of them undocumented (sent empty); re-check after a BUSY upgrade.\n\nCloud: no cloud route exists (Local API only).\n\nCanonical contract: `docs/LOCAL-API.md` section 5ak; `docs/features/BUSY-Report-PDF-2-API.md`."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"3c5e7a9b1d2f4a6c8e0b2d4f6a8c0e52","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"NOT_FOUND\",\n      \"message\": \"No Payment Reminder format of this company in BUSY has exactly that formatName (names are case-sensitive). Leave formatName out for STANDARD. Available: STANDARD.\",\n      \"field\": \"formatName\"\n    },\n    \"requestId\": \"3c5e7a9b1d2f4a6c8e0b2d4f6a8c0e52\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"efd6c259-3fc4-412d-350e-f0e79c358d6b","name":"409 – no STANDARD Payment Reminder format","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": {{customerId}} },\n  \"bills\": \"pending\",\n  \"itemDetails\": false,\n  \"boldDueBills\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/payment-reminder-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/payment-reminder-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Local** · `POST {{baseUrl}}/api/v1/payment-reminder-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ Native report-PDF side effects unverified\n**Required:** `companyCode`, `financialYear`, `account` · operation `busy.reports.payment-reminder.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Status (2026-10-16):** implemented and accepted for the Windows / Local API scope (the Payment Reminder PoC was accepted for one account); installed service-account acceptance passed 2026-10-16 (COMP0002 / FY 2026, values recalculated on the day, no table changed). Public builds up to 0.0.12 do not have the route and answer `404`. Re-checked by the 2026-10-18 Local API acceptance audit on the installed 0.0.14.\n\n---\n\n**`busy.reports.payment-reminder.pdf`** (`POST /api/v1/payment-reminder-pdf`). One customer's **Payment Reminder** letter printed by **BUSY's own report printing** (BUSY report 150) on this PC and returned as a PDF in `data.contentBase64` (standard base64, one line): To the customer, From the company, the balance of its pending (or due) bills as on a date, and the bill list with a grand total.\n\n**Variables:** the body uses `{{customerId}}`, which must be an account of `{{companyCode}}` that BUSY keeps **bill by bill** (COMP0002 = 1289). Or send `{\"name\": \"…\"}` instead of the code.\n\nRequest: `{ companyCode, financialYear, account, asOfDate?, bills?, formatName?, itemDetails?, boldDueBills? }`\n- `account`: `{code}` or `{name}` (an account master, not an alias), kept bill by bill, else `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`.\n- `asOfDate`: optional `YYYY-MM-DD` inside the selected financial year. Default: today in India, kept inside the year.\n- `bills`: optional, exact: `pending` (default; every outstanding bill) or `due` (outstanding and due on or before `asOfDate`).\n- `formatName`: optional, one of the company's Payment Reminder formats in BUSY, exactly as named (case-sensitive), 1-64 characters. Absent = `STANDARD`. An unknown name is `404 NOT_FOUND` (`field: formatName`, the message lists the company's formats); without `formatName` and without a `STANDARD` format `409 BUSY_PRINT_FORMAT_MISSING`. A format is never created and never replaced by another.\n- `itemDetails`: optional Boolean, default `false` (item lines under each invoice). `boldDueBills`: optional Boolean, default `true`.\n- Not offered: a group, several or all accounts, branch, series or optional-field filters, other BUSY switches (unknown members `400 BAD_REQUEST`).\n\nResponse (200): `data` = `{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }`, `fileName` `PaymentReminder-<company>-<year>-<code>-<asOf>-<bills>.pdf`. `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"paymentReminder\"), busyReportId (150), account {code, name}, asOfDate, bills, formatSource (\"default\" | \"selected\"), formatName, itemDetails, boldDueBills, elapsedMs, executedAt`.\n\nErrors: as the Account Ledger PDF, plus the format errors above and `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`. SQL Server companies only. One BUSY job at a time, up to 2 minutes: give the request a long timeout. Inspect the outcome and reconfirm before any repeat. At most 8 MiB (`422 RESULT_TOO_LARGE`, never cut).\n\nUpgrade note: BUSY reads 25 positions for this report on the installed BUSY version, 8 of them undocumented (sent empty); re-check after a BUSY upgrade.\n\nCloud: no cloud route exists (Local API only).\n\nCanonical contract: `docs/LOCAL-API.md` section 5ak; `docs/features/BUSY-Report-PDF-2-API.md`."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"9e1a3c5b7d0f2e4a6c8b0d2f4e6a8c63","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_PRINT_FORMAT_MISSING\",\n      \"message\": \"This company has no STANDARD Payment Reminder format in BUSY. AI Zeny never creates a format or uses another one instead. Set up the STANDARD Payment Reminder format in BUSY, or send formatName with one of the company's Payment Reminder formats.\",\n      \"field\": \"formatName\"\n    },\n    \"requestId\": \"9e1a3c5b7d0f2e4a6c8b0d2f4e6a8c63\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"3d6ef4ae-257d-f98e-e1e8-c9b6adf6c7e3"},{"name":"⚠ busy.reports.bills-payable.pdf – Bills Payable PDF","id":"a3ab5108-fc85-f326-7a68-27e0f4e35b9f","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": {{supplierId}} },\n  \"status\": \"pending\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/bills-payable-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /api/v1/bills-payable-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.</p>\n<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/bills-payable-pdf</code> · Bearer <code>{{localApiToken}}</code> (collection auth) · ⚠ Native report-PDF side effects unverified\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>account</code> · operation <code>busy.reports.bills-payable.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<p><strong>Status (2026-10-16):</strong> implemented and accepted for the Windows / Local API scope; installed service-account acceptance passed 2026-10-16 (COMP0002 / FY 2026, values recalculated on the day, no table changed). Public builds up to 0.0.12 do not have the route and answer <code>404</code>. Re-checked by the 2026-10-18 Local API acceptance audit on the installed 0.0.14.</p>\n<hr />\n<p><strong><code>busy.reports.bills-payable.pdf</code></strong> (<code>POST /api/v1/bills-payable-pdf</code>). One account's <strong>Bills Payable</strong> (bill-by-bill outstanding) report printed by <strong>BUSY's own report printing</strong> (BUSY report 201, payable side) on this PC and returned as a PDF in <code>data.contentBase64</code> (standard base64, one line). Values exactly as BUSY prints them: a bill paid more than its amount shows a <strong>negative</strong> pending amount. The supplier's advances and other debit references are <strong>not</strong> in this report and are <strong>not netted</strong> against its total (ask for the Bills Receivable PDF of the same account to see them).</p>\n<p><strong>Variables:</strong> the body uses <code>{{supplierId}}</code>, which must be a supplier account of <code>{{companyCode}}</code> that BUSY keeps <strong>bill by bill</strong> (COMP0002 = 1292). Or send <code>{\"name\": \"…\"}</code> instead of the code.</p>\n<p>Request: <code>{ companyCode, financialYear, account, asOfDate?, status? }</code> — the same members and rules as the Bills Receivable PDF:</p>\n<ul>\n<li><code>account</code>: <code>{code}</code> or <code>{name}</code> (an account master, not an alias), kept bill by bill, else <code>422 REPORT_ACCOUNT_NOT_BILL_BY_BILL</code>.</li>\n<li><code>asOfDate</code>: optional <code>YYYY-MM-DD</code> inside the selected financial year. Default: today in India, kept inside the year.</li>\n<li><code>status</code>: optional, exact: <code>pending</code> (default), <code>overdue</code> (outstanding and due on or before <code>asOfDate</code>), <code>all</code>.</li>\n<li>Not offered: the receivable side (use <code>/bills-receivable-pdf</code>), all accounts at once, BUSY's start date, format, ageing, sorting or column options (unknown members <code>400 BAD_REQUEST</code>).</li>\n</ul>\n<p>Response (200): <code>data</code> = <code>{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }</code>, <code>fileName</code> <code>BillsPayable-&lt;company&gt;-&lt;year&gt;-&lt;code&gt;-&lt;asOf&gt;-&lt;status&gt;.pdf</code>. <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, report (\"billsPayable\"), busyReportId (201), account {code, name}, asOfDate, status, elapsedMs, executedAt</code>.</p>\n<p>Errors: as the Bills Receivable PDF. SQL Server companies only. One BUSY job at a time, up to 2 minutes: give the request a long timeout. Inspect the outcome and reconfirm before any repeat. At most 8 MiB (<code>422 RESULT_TOO_LARGE</code>, never cut).</p>\n<p>Cloud: no cloud route exists (Local API only).</p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5ak; <code>docs/features/BUSY-Report-PDF-2-API.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","bills-payable-pdf"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"c6120a18-5725-3cb5-7056-bdcecd2c553f","name":"200 – payable bills, all (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": {{supplierId}} },\n  \"status\": \"pending\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/bills-payable-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/bills-payable-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Local** · `POST {{baseUrl}}/api/v1/bills-payable-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ Native report-PDF side effects unverified\n**Required:** `companyCode`, `financialYear`, `account` · operation `busy.reports.bills-payable.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Status (2026-10-16):** implemented and accepted for the Windows / Local API scope; installed service-account acceptance passed 2026-10-16 (COMP0002 / FY 2026, values recalculated on the day, no table changed). Public builds up to 0.0.12 do not have the route and answer `404`. Re-checked by the 2026-10-18 Local API acceptance audit on the installed 0.0.14.\n\n---\n\n**`busy.reports.bills-payable.pdf`** (`POST /api/v1/bills-payable-pdf`). One account's **Bills Payable** (bill-by-bill outstanding) report printed by **BUSY's own report printing** (BUSY report 201, payable side) on this PC and returned as a PDF in `data.contentBase64` (standard base64, one line). Values exactly as BUSY prints them: a bill paid more than its amount shows a **negative** pending amount. The supplier's advances and other debit references are **not** in this report and are **not netted** against its total (ask for the Bills Receivable PDF of the same account to see them).\n\n**Variables:** the body uses `{{supplierId}}`, which must be a supplier account of `{{companyCode}}` that BUSY keeps **bill by bill** (COMP0002 = 1292). Or send `{\"name\": \"…\"}` instead of the code.\n\nRequest: `{ companyCode, financialYear, account, asOfDate?, status? }` — the same members and rules as the Bills Receivable PDF:\n- `account`: `{code}` or `{name}` (an account master, not an alias), kept bill by bill, else `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`.\n- `asOfDate`: optional `YYYY-MM-DD` inside the selected financial year. Default: today in India, kept inside the year.\n- `status`: optional, exact: `pending` (default), `overdue` (outstanding and due on or before `asOfDate`), `all`.\n- Not offered: the receivable side (use `/bills-receivable-pdf`), all accounts at once, BUSY's start date, format, ageing, sorting or column options (unknown members `400 BAD_REQUEST`).\n\nResponse (200): `data` = `{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }`, `fileName` `BillsPayable-<company>-<year>-<code>-<asOf>-<status>.pdf`. `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"billsPayable\"), busyReportId (201), account {code, name}, asOfDate, status, elapsedMs, executedAt`.\n\nErrors: as the Bills Receivable PDF. SQL Server companies only. One BUSY job at a time, up to 2 minutes: give the request a long timeout. Inspect the outcome and reconfirm before any repeat. At most 8 MiB (`422 RESULT_TOO_LARGE`, never cut).\n\nCloud: no cloud route exists (Local API only).\n\nCanonical contract: `docs/LOCAL-API.md` section 5ak; `docs/features/BUSY-Report-PDF-2-API.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"2b4d6f8a0c1e3a5c7e9b1d3f5a7c9e74","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"fileName\": \"BillsPayable-COMP0002-2026-7201-2026-10-16-all.pdf\",\n    \"mimeType\": \"application/pdf\",\n    \"byteLength\": 54,\n    \"sha256\": \"489ffb43555619d787dcc6b7d2117d4a061970f975a531e413b8b4f74f4ca303\",\n    \"pages\": 1,\n    \"contentBase64\": \"JVBERi0xLjQKJSBzeW50aGV0aWMgZXhhbXBsZSwgbm90IGEgcmVhbCByZXBvcnQKJSVFT0YK\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.reports.bills-payable.pdf\",\n    \"requestId\": \"2b4d6f8a0c1e3a5c7e9b1d3f5a7c9e74\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"report\": \"billsPayable\",\n    \"busyReportId\": 201,\n    \"account\": { \"code\": 7201, \"name\": \"Synthetic Supplies\" },\n    \"asOfDate\": \"2026-10-16\",\n    \"status\": \"all\",\n    \"elapsedMs\": 3880,\n    \"executedAt\": \"2026-10-16T07:31:00.0000000Z\"\n  }\n}"},{"id":"30fee18d-d056-755e-f301-0ba024f2ad56","name":"422 – account not kept bill by bill","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": {{supplierId}} },\n  \"status\": \"pending\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/bills-payable-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /api/v1/bills-payable-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Local** · `POST {{baseUrl}}/api/v1/bills-payable-pdf` · Bearer `{{localApiToken}}` (collection auth) · ⚠ Native report-PDF side effects unverified\n**Required:** `companyCode`, `financialYear`, `account` · operation `busy.reports.bills-payable.pdf`\n**Answer:** `{ success, data, metadata }` (errors: `success: false`, `data: null`, `metadata.error`).\n\n**Status (2026-10-16):** implemented and accepted for the Windows / Local API scope; installed service-account acceptance passed 2026-10-16 (COMP0002 / FY 2026, values recalculated on the day, no table changed). Public builds up to 0.0.12 do not have the route and answer `404`. Re-checked by the 2026-10-18 Local API acceptance audit on the installed 0.0.14.\n\n---\n\n**`busy.reports.bills-payable.pdf`** (`POST /api/v1/bills-payable-pdf`). One account's **Bills Payable** (bill-by-bill outstanding) report printed by **BUSY's own report printing** (BUSY report 201, payable side) on this PC and returned as a PDF in `data.contentBase64` (standard base64, one line). Values exactly as BUSY prints them: a bill paid more than its amount shows a **negative** pending amount. The supplier's advances and other debit references are **not** in this report and are **not netted** against its total (ask for the Bills Receivable PDF of the same account to see them).\n\n**Variables:** the body uses `{{supplierId}}`, which must be a supplier account of `{{companyCode}}` that BUSY keeps **bill by bill** (COMP0002 = 1292). Or send `{\"name\": \"…\"}` instead of the code.\n\nRequest: `{ companyCode, financialYear, account, asOfDate?, status? }` — the same members and rules as the Bills Receivable PDF:\n- `account`: `{code}` or `{name}` (an account master, not an alias), kept bill by bill, else `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`.\n- `asOfDate`: optional `YYYY-MM-DD` inside the selected financial year. Default: today in India, kept inside the year.\n- `status`: optional, exact: `pending` (default), `overdue` (outstanding and due on or before `asOfDate`), `all`.\n- Not offered: the receivable side (use `/bills-receivable-pdf`), all accounts at once, BUSY's start date, format, ageing, sorting or column options (unknown members `400 BAD_REQUEST`).\n\nResponse (200): `data` = `{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }`, `fileName` `BillsPayable-<company>-<year>-<code>-<asOf>-<status>.pdf`. `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"billsPayable\"), busyReportId (201), account {code, name}, asOfDate, status, elapsedMs, executedAt`.\n\nErrors: as the Bills Receivable PDF. SQL Server companies only. One BUSY job at a time, up to 2 minutes: give the request a long timeout. Inspect the outcome and reconfirm before any repeat. At most 8 MiB (`422 RESULT_TOO_LARGE`, never cut).\n\nCloud: no cloud route exists (Local API only).\n\nCanonical contract: `docs/LOCAL-API.md` section 5ak; `docs/features/BUSY-Report-PDF-2-API.md`."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"6d8f0a2c4e1b3d5f7a9c1e3b5d7f9a85","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"REPORT_ACCOUNT_NOT_BILL_BY_BILL\",\n      \"message\": \"BUSY does not keep this account bill by bill, so it has no bill-wise payables. Use the Account Ledger PDF for it.\",\n      \"field\": \"account\"\n    },\n    \"requestId\": \"6d8f0a2c4e1b3d5f7a9c1e3b5d7f9a85\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"a3ab5108-fc85-f326-7a68-27e0f4e35b9f"}],"id":"5a0aa9a3-af45-b2a1-0b6b-6eb9874b2e37","description":"<p>BUSY report printing returns a PDF. Native report-PDF side effects have not been independently established; treat these requests as potentially mutating and require explicit one-send confirmation.</p>\n","_postman_id":"5a0aa9a3-af45-b2a1-0b6b-6eb9874b2e37","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Catalogue Designs & Photo Sources (read only)","item":[{"name":"Catalogue designs – list","id":"19590a4b-2762-5ab5-7ec3-0edd80c7e7ce","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/catalogue-templates","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/busy/catalogue-templates</code> · Bearer token · Read only — does not write to BUSY</p>\n<p>Every catalogue design without its source: the three read-only built-ins and your own designs (<code>name</code>, <code>kind</code>, <code>description</code>, <code>basedOn</code>, <code>basedOnRevision</code>, <code>status</code>, <code>page</code>, <code>revision</code>, <code>updatedUtc</code>, and last <code>builtInId</code>).</p>\n<p><strong><code>builtInId</code></strong> (added 2026-10-18) is a built-in's stable id (<code>grid-cards</code>, <code>photo-list</code>, <code>price-list</code>); your own designs carry <code>null</code>. To copy a built-in, send its <code>builtInId</code> as <code>basedOn</code> and its <code>revision</code> as <code>basedOnRevision</code> (see <strong>⚠ Catalogue design – create (copy of a built-in)</strong>). The display name is not accepted as <code>basedOn</code>. A Host installed before this change does not send <code>builtInId</code>; the test then skips that check.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","catalogue-templates"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"4d36e775-8443-fd76-3047-f2fb661b1b19","name":"200 – three built-ins and one customer design (synthetic)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/catalogue-templates","description":"**Local** · `GET {{baseUrl}}/api/v1/busy/catalogue-templates` · Bearer token · Read only — does not write to BUSY\n\nEvery catalogue design without its source: the three read-only built-ins and your own designs (`name`, `kind`, `description`, `basedOn`, `basedOnRevision`, `status`, `page`, `revision`, `updatedUtc`, and last `builtInId`).\n\n**`builtInId`** (added 2026-10-18) is a built-in's stable id (`grid-cards`, `photo-list`, `price-list`); your own designs carry `null`. To copy a built-in, send its `builtInId` as `basedOn` and its `revision` as `basedOnRevision` (see **⚠ Catalogue design – create (copy of a built-in)**). The display name is not accepted as `basedOn`. A Host installed before this change does not send `builtInId`; the test then skips that check."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"0b6f0c1d2e3f40516273849a5b6c7d8e"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    { \"name\": \"Grid cards\", \"kind\": \"builtIn\", \"description\": \"A4, 3 x 3 photo cards per page, prices and stock\", \"basedOn\": null, \"basedOnRevision\": null, \"status\": \"valid\", \"page\": \"A4 portrait\", \"revision\": 1, \"updatedUtc\": null, \"builtInId\": \"grid-cards\" },\n    { \"name\": \"Photo list\", \"kind\": \"builtIn\", \"description\": \"A4, one product per row with a photo\", \"basedOn\": null, \"basedOnRevision\": null, \"status\": \"valid\", \"page\": \"A4 portrait\", \"revision\": 1, \"updatedUtc\": null, \"builtInId\": \"photo-list\" },\n    { \"name\": \"Price list\", \"kind\": \"builtIn\", \"description\": \"A4, a compact price table\", \"basedOn\": null, \"basedOnRevision\": null, \"status\": \"valid\", \"page\": \"A4 portrait\", \"revision\": 1, \"updatedUtc\": null, \"builtInId\": \"price-list\" },\n    { \"name\": \"Sample shop cards\", \"kind\": \"custom\", \"description\": null, \"basedOn\": \"grid-cards\", \"basedOnRevision\": 1, \"status\": \"valid\", \"page\": \"A4 portrait\", \"revision\": 3, \"updatedUtc\": \"2026-10-18T06:00:00Z\", \"builtInId\": null }\n  ],\n  \"metadata\": { \"count\": 4, \"builtIn\": 3, \"custom\": 1, \"templateVersion\": 1 }\n}"}],"_postman_id":"19590a4b-2762-5ab5-7ec3-0edd80c7e7ce"},{"name":"Catalogue design – view (with source)","id":"8d7ec7b5-be58-d8f2-616e-6375c920eeb8","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/catalogue-templates/{{catalogueTemplateName}}","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/busy/catalogue-templates/{{catalogueTemplateName}}</code> · Bearer (collection auth) · Read only</p>\n<hr />\n<p>One design with its HTML <code>source</code> (built-ins included). <code>data</code> = the list's members plus <code>source</code>, <code>templateVersion</code>, <code>diagnostics</code> (the validator's errors and warnings with line and column), <code>createdUtc</code>. <code>404 CATALOGUE_TEMPLATE_NOT_FOUND</code> for an unknown name (compared without case). <code>catalogueTemplateName</code> defaults to <code>Grid cards</code>.</p>\n<p>The source is never logged by the Host. Contract: <code>docs/LOCAL-API.md</code> section 5y.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","catalogue-templates","{{catalogueTemplateName}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"9b011fac-cb7e-2bf9-a031-448749c6e963","name":"404 – no design with that name (synthetic)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/catalogue-templates/{{catalogueTemplateName}}","description":"**Local** · `GET {{baseUrl}}/api/v1/busy/catalogue-templates/{{catalogueTemplateName}}` · Bearer (collection auth) · Read only\n\n---\n\nOne design with its HTML `source` (built-ins included). `data` = the list's members plus `source`, `templateVersion`, `diagnostics` (the validator's errors and warnings with line and column), `createdUtc`. `404 CATALOGUE_TEMPLATE_NOT_FOUND` for an unknown name (compared without case). `catalogueTemplateName` defaults to `Grid cards`.\n\nThe source is never logged by the Host. Contract: `docs/LOCAL-API.md` section 5y."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"1c7a0d2e3f4051627384950a6b7c8d9e"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": { \"code\": \"CATALOGUE_TEMPLATE_NOT_FOUND\", \"message\": \"There is no catalogue design with that name.\", \"field\": \"name\" },\n    \"requestId\": \"1c7a0d2e3f4051627384950a6b7c8d9e\"\n  }\n}"},{"id":"20ae277a-1d04-4559-07ac-fc64d5183e72","name":"200 – a built-in with its builtInId (synthetic)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/catalogue-templates/{{catalogueTemplateName}}","description":"**Local** · `GET {{baseUrl}}/api/v1/busy/catalogue-templates/{{catalogueTemplateName}}` · Bearer (collection auth) · Read only\n\n---\n\nOne design with its HTML `source` (built-ins included). `data` = the list's members plus `source`, `templateVersion`, `diagnostics` (the validator's errors and warnings with line and column), `createdUtc`. `404 CATALOGUE_TEMPLATE_NOT_FOUND` for an unknown name (compared without case). `catalogueTemplateName` defaults to `Grid cards`.\n\nThe source is never logged by the Host. Contract: `docs/LOCAL-API.md` section 5y."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"5e6f708192a3b4c5d6e7f8091a2b3c4d","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"name\": \"Grid cards\",\n    \"kind\": \"builtIn\",\n    \"basedOn\": null,\n    \"basedOnRevision\": null,\n    \"templateVersion\": 1,\n    \"status\": \"valid\",\n    \"page\": \"A4 portrait\",\n    \"source\": \"<!DOCTYPE html>…\",\n    \"diagnostics\": [],\n    \"revision\": 1,\n    \"createdUtc\": null,\n    \"updatedUtc\": null,\n    \"builtInId\": \"grid-cards\"\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"8d7ec7b5-be58-d8f2-616e-6375c920eeb8"},{"name":"Catalogue design – validate a draft (nothing stored)","id":"464daa5c-7690-ad35-ae37-eac5e19341b8","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"source\": \"<!DOCTYPE html>\\n<html><head><meta charset=\\\"utf-8\\\"><title>{{ catalogue.title }}</title></head>\\n<body>\\n{{#each products}}<p>{{ product.name }}</p>{{/each}}\\n</body></html>\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/catalogue-templates/validate","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/catalogue-templates/validate</code> · Bearer (collection auth) · Read only — <strong>nothing is stored</strong> (a POST that only checks)</p>\n<hr />\n<p>Runs the same validator the window runs as you type and answers <code>data</code> = <code>{ status (\"valid\" | \"needsFixing\"), placeholderCount, diagnostics: [{ severity, code, message, line, column, suggestion? }] }</code>. Body <code>{ source }</code> (at most 1 MiB of UTF-8; bodies up to 4 MiB). Note: Postman would replace <code>{{ … }}</code> in a raw body with environment variables — the sample uses names no environment defines, so they reach the Host as written.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5y; placeholder language <code>docs/public/busy/catalogue-placeholders.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","catalogue-templates","validate"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"55945908-4b86-6d52-55a5-10c767e0dc1e","name":"200 – a draft that needs fixing (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"source\": \"<!DOCTYPE html>\\n<html><head><meta charset=\\\"utf-8\\\"><title>{{ catalogue.title }}</title></head>\\n<body>\\n{{#each products}}<p>{{ product.name }}</p>{{/each}}\\n</body></html>\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/catalogue-templates/validate","description":"**Local** · `POST {{baseUrl}}/api/v1/busy/catalogue-templates/validate` · Bearer (collection auth) · Read only — **nothing is stored** (a POST that only checks)\n\n---\n\nRuns the same validator the window runs as you type and answers `data` = `{ status (\"valid\" | \"needsFixing\"), placeholderCount, diagnostics: [{ severity, code, message, line, column, suggestion? }] }`. Body `{ source }` (at most 1 MiB of UTF-8; bodies up to 4 MiB). Note: Postman would replace `{{ … }}` in a raw body with environment variables — the sample uses names no environment defines, so they reach the Host as written.\n\nContract: `docs/LOCAL-API.md` section 5y; placeholder language `docs/public/busy/catalogue-placeholders.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"2d8b1e3f405162738495a60b7c8d9e0f","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"status\": \"needsFixing\",\n    \"placeholderCount\": 3,\n    \"diagnostics\": [\n      { \"severity\": \"error\", \"code\": \"UNKNOWN_FIELD\", \"message\": \"product.salePrise is not a field. Did you mean product.salesPrice?\", \"line\": 4, \"column\": 18, \"suggestion\": \"product.salesPrice\" }\n    ]\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"464daa5c-7690-ad35-ae37-eac5e19341b8"},{"name":"Catalogue photo source – view","id":"b8455d5f-45c3-4999-7b98-a5c4ccba2432","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/catalogue-photo-sources/{{companyCode}}","description":"<p><strong>Local</strong> · <code>GET {{baseUrl}}/api/v1/busy/catalogue-photo-sources/{{companyCode}}</code> · Bearer (collection auth) · Read only</p>\n<hr />\n<p>The company's catalogue photo settings: <code>data</code> = <code>{ companyCode, folder, includeSubfolders, matchBy: [code | name | alias | printName | multipleAliases] (stored in that fixed order), updatedUtc }</code>. <code>404 CATALOGUE_PHOTO_SOURCE_NOT_FOUND</code> when none is saved (the normal answer on this PC), <code>404 BUSY_COMPANY_NOT_FOUND</code> for an unknown company. The folder is never logged.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5y.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","catalogue-photo-sources","{{companyCode}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"e3264e9a-eae7-ad9b-1133-046c8cfa3431","name":"404 – no photo source saved (the normal answer)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/catalogue-photo-sources/{{companyCode}}","description":"**Local** · `GET {{baseUrl}}/api/v1/busy/catalogue-photo-sources/{{companyCode}}` · Bearer (collection auth) · Read only\n\n---\n\nThe company's catalogue photo settings: `data` = `{ companyCode, folder, includeSubfolders, matchBy: [code | name | alias | printName | multipleAliases] (stored in that fixed order), updatedUtc }`. `404 CATALOGUE_PHOTO_SOURCE_NOT_FOUND` when none is saved (the normal answer on this PC), `404 BUSY_COMPANY_NOT_FOUND` for an unknown company. The folder is never logged.\n\nContract: `docs/LOCAL-API.md` section 5y."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"3e9c2f405162738495a6b70c8d9e0f1a","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": { \"code\": \"CATALOGUE_PHOTO_SOURCE_NOT_FOUND\", \"message\": \"No catalogue photo folder is saved for this company.\" },\n    \"requestId\": \"3e9c2f405162738495a6b70c8d9e0f1a\"\n  }\n}"}],"_postman_id":"b8455d5f-45c3-4999-7b98-a5c4ccba2432"}],"id":"56172af4-0d1d-866f-f927-7270448dfe69","_postman_id":"56172af4-0d1d-866f-f927-7270448dfe69","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ PC Settings — Catalogue Designs & Photo Sources (changes AI Zeny, not BUSY)","item":[{"name":"⚠ Catalogue design – create (copy of a built-in)","id":"b46f5f76-5eeb-7cc0-d308-f7ebdc70f07f","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"name\": \"{{catalogueNewDesignName}}\",\n  \"source\": \"<!DOCTYPE html>\\n<html><head><meta charset=\\\"utf-8\\\"><title>{{ catalogue.title }}</title></head>\\n<body>\\n{{#each products}}<p>{{ product.name }}</p>{{/each}}\\n</body></html>\",\n  \"basedOn\": \"grid-cards\",\n  \"basedOnRevision\": 1\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/catalogue-templates","description":"<p><strong>Local</strong> · <code>POST {{baseUrl}}/api/v1/busy/catalogue-templates</code> · Bearer token · ⚠ Changes AI Zeny's own settings (a new catalogue design), not BUSY. Guarded: sends only with <code>confirmMutating = yes</code> and a new <code>catalogueNewDesignName</code>.</p>\n<p>Saves a copy of a built-in design. <code>basedOn</code> is the built-in's <strong><code>builtInId</code></strong> and <code>basedOnRevision</code> its <code>revision</code>, both read from <strong>Catalogue designs – list</strong> (<code>grid-cards</code> / revision 1 here). The <code>source</code> usually starts from <strong>Catalogue design – view (with source)</strong> of that built-in. The display name (\"Grid cards\") is refused as <code>basedOn</code> (<code>422 CATALOGUE_TEMPLATE_INVALID</code>, <code>field: basedOn</code>). Without <code>basedOn</code> the design is saved as your own, with no origin recorded.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","catalogue-templates"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"6a7a57dd-bf39-0e60-241e-6be3ab66dd33","name":"200 – design saved (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"name\": \"{{catalogueNewDesignName}}\",\n  \"source\": \"<!DOCTYPE html>\\n<html><head><meta charset=\\\"utf-8\\\"><title>{{ catalogue.title }}</title></head>\\n<body>\\n{{#each products}}<p>{{ product.name }}</p>{{/each}}\\n</body></html>\",\n  \"basedOn\": \"grid-cards\",\n  \"basedOnRevision\": 1\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/catalogue-templates","description":"**Local** · `POST {{baseUrl}}/api/v1/busy/catalogue-templates` · Bearer token · ⚠ Changes AI Zeny's own settings (a new catalogue design), not BUSY. Guarded: sends only with `confirmMutating = yes` and a new `catalogueNewDesignName`.\n\nSaves a copy of a built-in design. `basedOn` is the built-in's **`builtInId`** and `basedOnRevision` its `revision`, both read from **Catalogue designs – list** (`grid-cards` / revision 1 here). The `source` usually starts from **Catalogue design – view (with source)** of that built-in. The display name (\"Grid cards\") is refused as `basedOn` (`422 CATALOGUE_TEMPLATE_INVALID`, `field: basedOn`). Without `basedOn` the design is saved as your own, with no origin recorded."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"4fad30516273849506a7b8c9d0e1f2a3","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"name\": \"Sample shop cards\",\n    \"kind\": \"custom\",\n    \"basedOn\": \"grid-cards\",\n    \"basedOnRevision\": 1,\n    \"templateVersion\": 1,\n    \"status\": \"valid\",\n    \"page\": \"custom\",\n    \"source\": \"<!DOCTYPE html>…\",\n    \"diagnostics\": [],\n    \"revision\": 1,\n    \"createdUtc\": \"2026-10-18T06:00:00Z\",\n    \"updatedUtc\": \"2026-10-18T06:00:00Z\",\n    \"builtInId\": null\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"b46f5f76-5eeb-7cc0-d308-f7ebdc70f07f"},{"name":"⚠ Catalogue design – change","id":"c11d1c43-659e-4a9c-e139-3ad996b7dde0","request":{"method":"PUT","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"source\": \"<!DOCTYPE html>\\n<html><head><meta charset=\\\"utf-8\\\"><title>{{ catalogue.title }}</title></head>\\n<body>\\n{{#each products}}<p>{{ product.name }} {{ product.salesPrice | money }}</p>{{/each}}\\n</body></html>\",\n  \"expectedRevision\": {{catalogueTemplateRevision}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/catalogue-templates/{{catalogueNewDesignName}}","description":"<p><strong>Local</strong> · <code>PUT {{baseUrl}}/api/v1/busy/catalogue-templates/{{catalogueNewDesignName}}</code> · Bearer (collection auth) · <strong>Changes AI Zeny on the PC</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Replaces a customer design's source (and optionally <code>name</code>). Body <code>{ source, expectedRevision, name? }</code>; <code>basedOn</code> cannot change. Refusals: <code>403 CATALOGUE_TEMPLATE_BUILT_IN</code> (a built-in is read only), <code>404 CATALOGUE_TEMPLATE_NOT_FOUND</code>, <code>409 CATALOGUE_TEMPLATE_CHANGED</code> (a stale <code>expectedRevision</code>: nothing overwritten), <code>422 CATALOGUE_TEMPLATE_INVALID</code>. Skipped while <code>catalogueNewDesignName</code> or <code>catalogueTemplateRevision</code> is empty.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5y.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","catalogue-templates","{{catalogueNewDesignName}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"d826ac64-20fc-fbea-8df2-a1d57f19ad02","name":"409 – changed in the meantime: nothing overwritten (synthetic)","originalRequest":{"method":"PUT","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"source\": \"<!DOCTYPE html>\\n<html><head><meta charset=\\\"utf-8\\\"><title>{{ catalogue.title }}</title></head>\\n<body>\\n{{#each products}}<p>{{ product.name }} {{ product.salesPrice | money }}</p>{{/each}}\\n</body></html>\",\n  \"expectedRevision\": {{catalogueTemplateRevision}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/catalogue-templates/{{catalogueNewDesignName}}","description":"**Local** · `PUT {{baseUrl}}/api/v1/busy/catalogue-templates/{{catalogueNewDesignName}}` · Bearer (collection auth) · **Changes AI Zeny on the PC** (guarded by `confirmMutating`)\n\n---\n\n**Mutating — run manually.** Replaces a customer design's source (and optionally `name`). Body `{ source, expectedRevision, name? }`; `basedOn` cannot change. Refusals: `403 CATALOGUE_TEMPLATE_BUILT_IN` (a built-in is read only), `404 CATALOGUE_TEMPLATE_NOT_FOUND`, `409 CATALOGUE_TEMPLATE_CHANGED` (a stale `expectedRevision`: nothing overwritten), `422 CATALOGUE_TEMPLATE_INVALID`. Skipped while `catalogueNewDesignName` or `catalogueTemplateRevision` is empty.\n\nContract: `docs/LOCAL-API.md` section 5y."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"50be41627384950617b8c9d0e1f2a3b4"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": { \"code\": \"CATALOGUE_TEMPLATE_CHANGED\", \"message\": \"The design was changed since you read it; nothing was overwritten. Read it again.\", \"field\": \"expectedRevision\" },\n    \"requestId\": \"50be41627384950617b8c9d0e1f2a3b4\"\n  }\n}"}],"_postman_id":"c11d1c43-659e-4a9c-e139-3ad996b7dde0"},{"name":"⚠ Catalogue design – delete","id":"d7721cc0-7e9a-e1e9-bae3-c5da4e5b22f0","request":{"method":"DELETE","header":[],"url":"{{baseUrl}}/api/v1/busy/catalogue-templates/{{catalogueNewDesignName}}?revision={{catalogueTemplateRevision}}","description":"<p><strong>Local</strong> · <code>DELETE {{baseUrl}}/api/v1/busy/catalogue-templates/{{catalogueNewDesignName}}?revision=…</code> · Bearer (collection auth) · <strong>Changes AI Zeny on the PC</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Deletes one customer design permanently (no undo: copy its source first with 'Catalogue design – view'). Built-ins cannot be deleted (<code>403 CATALOGUE_TEMPLATE_BUILT_IN</code>); a stale revision is <code>409 CATALOGUE_TEMPLATE_CHANGED</code>. Answer 200 = what was removed. Skipped while the name or revision is empty.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5y.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","catalogue-templates","{{catalogueNewDesignName}}"],"host":["{{baseUrl}}"],"query":[{"description":{"content":"<p>the revision you read (required; a stale one is 409 and nothing is deleted)</p>\n","type":"text/plain"},"key":"revision","value":"{{catalogueTemplateRevision}}"}],"variable":[]}},"response":[{"id":"9d34c1fd-7f18-0672-cd83-7c7aa116d764","name":"403 – a built-in cannot be deleted (synthetic)","originalRequest":{"method":"DELETE","header":[],"url":{"raw":"{{baseUrl}}/api/v1/busy/catalogue-templates/{{catalogueNewDesignName}}?revision={{catalogueTemplateRevision}}","host":["{{baseUrl}}"],"path":["api","v1","busy","catalogue-templates","{{catalogueNewDesignName}}"],"query":[{"value":"{{catalogueTemplateRevision}}","key":"revision","description":"the revision you read (required; a stale one is 409 and nothing is deleted)"}]},"description":"**Local** · `DELETE {{baseUrl}}/api/v1/busy/catalogue-templates/{{catalogueNewDesignName}}?revision=…` · Bearer (collection auth) · **Changes AI Zeny on the PC** (guarded by `confirmMutating`)\n\n---\n\n**Mutating — run manually.** Deletes one customer design permanently (no undo: copy its source first with 'Catalogue design – view'). Built-ins cannot be deleted (`403 CATALOGUE_TEMPLATE_BUILT_IN`); a stale revision is `409 CATALOGUE_TEMPLATE_CHANGED`. Answer 200 = what was removed. Skipped while the name or revision is empty.\n\nContract: `docs/LOCAL-API.md` section 5y."},"status":"Forbidden","code":403,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"61cf527384950617a8c9d0e1f2a3b4c5"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": { \"code\": \"CATALOGUE_TEMPLATE_BUILT_IN\", \"message\": \"Built-in designs are read only. Copy it to make your own.\" },\n    \"requestId\": \"61cf527384950617a8c9d0e1f2a3b4c5\"\n  }\n}"}],"_postman_id":"d7721cc0-7e9a-e1e9-bae3-c5da4e5b22f0"},{"name":"⚠ Catalogue photo source – save","id":"da49138e-db82-a6f1-a397-815182a69bf2","request":{"method":"PUT","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"folder\": \"{{photoSourceFolder}}\",\n  \"includeSubfolders\": true,\n  \"matchBy\": [\"code\", \"name\"]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/catalogue-photo-sources/{{companyCode}}","description":"<p><strong>Local</strong> · <code>PUT {{baseUrl}}/api/v1/busy/catalogue-photo-sources/{{companyCode}}</code> · Bearer (collection auth) · <strong>Changes AI Zeny on the PC</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Adds or replaces the company's catalogue photo settings. Body <code>{ folder, includeSubfolders?, matchBy? }</code>: <code>folder</code> an absolute local or UNC folder of at most 240 characters (no wildcard, control character, <code>.</code> or <code>..</code> part); <code>matchBy</code> each of <code>code</code>, <code>name</code>, <code>alias</code>, <code>printName</code>, <code>multipleAliases</code> at most once (absent = code, name, alias; stored in that fixed order). The Host never reads the folder (the window scans it as the signed-in user). Refusals: <code>422 CATALOGUE_PHOTO_SOURCE_INVALID</code> (<code>field: folder | matchBy</code>), <code>400 BAD_REQUEST</code> (unknown member), <code>404 BUSY_COMPANY_NOT_FOUND</code>. Skipped while <code>photoSourceFolder</code> is empty.</p>\n<p><strong>Undo:</strong> '⚠ Catalogue photo source – remove'. Contract: <code>docs/LOCAL-API.md</code> section 5y.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","catalogue-photo-sources","{{companyCode}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"d930b69f-9e54-8e7f-bd7a-9b8918f30b14","name":"422 – folder not absolute (synthetic)","originalRequest":{"method":"PUT","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"folder\": \"{{photoSourceFolder}}\",\n  \"includeSubfolders\": true,\n  \"matchBy\": [\"code\", \"name\"]\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/busy/catalogue-photo-sources/{{companyCode}}","description":"**Local** · `PUT {{baseUrl}}/api/v1/busy/catalogue-photo-sources/{{companyCode}}` · Bearer (collection auth) · **Changes AI Zeny on the PC** (guarded by `confirmMutating`)\n\n---\n\n**Mutating — run manually.** Adds or replaces the company's catalogue photo settings. Body `{ folder, includeSubfolders?, matchBy? }`: `folder` an absolute local or UNC folder of at most 240 characters (no wildcard, control character, `.` or `..` part); `matchBy` each of `code`, `name`, `alias`, `printName`, `multipleAliases` at most once (absent = code, name, alias; stored in that fixed order). The Host never reads the folder (the window scans it as the signed-in user). Refusals: `422 CATALOGUE_PHOTO_SOURCE_INVALID` (`field: folder | matchBy`), `400 BAD_REQUEST` (unknown member), `404 BUSY_COMPANY_NOT_FOUND`. Skipped while `photoSourceFolder` is empty.\n\n**Undo:** '⚠ Catalogue photo source – remove'. Contract: `docs/LOCAL-API.md` section 5y."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"72d06384950617a8b9c0d1e2f3a4b5c6"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": { \"code\": \"CATALOGUE_PHOTO_SOURCE_INVALID\", \"message\": \"The photo folder must be an absolute local or network folder.\", \"field\": \"folder\" },\n    \"requestId\": \"72d06384950617a8b9c0d1e2f3a4b5c6\"\n  }\n}"}],"_postman_id":"da49138e-db82-a6f1-a397-815182a69bf2"},{"name":"⚠ Catalogue photo source – remove","id":"56f87d9c-c99e-5541-4f5b-53876042134d","request":{"method":"DELETE","header":[],"url":"{{baseUrl}}/api/v1/busy/catalogue-photo-sources/{{companyCode}}","description":"<p><strong>Local</strong> · <code>DELETE {{baseUrl}}/api/v1/busy/catalogue-photo-sources/{{companyCode}}</code> · Bearer (collection auth) · <strong>Changes AI Zeny on the PC</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Removes the company's photo settings (catalogues then have no photos); the photo files are not touched. Answer 200 = what was removed; <code>404 CATALOGUE_PHOTO_SOURCE_NOT_FOUND</code> when none is saved.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5y.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","catalogue-photo-sources","{{companyCode}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"72e8f650-386a-82ca-aa18-77c75acd7772","name":"200 – photo settings removed (synthetic)","originalRequest":{"method":"DELETE","header":[],"url":"{{baseUrl}}/api/v1/busy/catalogue-photo-sources/{{companyCode}}","description":"**Local** · `DELETE {{baseUrl}}/api/v1/busy/catalogue-photo-sources/{{companyCode}}` · Bearer (collection auth) · **Changes AI Zeny on the PC** (guarded by `confirmMutating`)\n\n---\n\n**Mutating — run manually.** Removes the company's photo settings (catalogues then have no photos); the photo files are not touched. Answer 200 = what was removed; `404 CATALOGUE_PHOTO_SOURCE_NOT_FOUND` when none is saved.\n\nContract: `docs/LOCAL-API.md` section 5y."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"83e1749506a7b8c9d0e1f2a3b4c5d6e7","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"companyCode\": \"COMP0002\", \"folder\": \"D:\\\\Example\\\\Photos\", \"includeSubfolders\": true, \"matchBy\": [\"code\", \"name\"], \"updatedUtc\": \"2026-10-18T06:00:00Z\" },\n  \"metadata\": {}\n}"}],"_postman_id":"56f87d9c-c99e-5541-4f5b-53876042134d"}],"id":"960e6f01-ef44-3e1b-da72-70df9693de0d","_postman_id":"960e6f01-ef44-3e1b-da72-70df9693de0d","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Upload, Google & Backup Status (read only — this PC only)","item":[{"name":"Cloud data upload – status","id":"11ae5c8e-671d-00d3-989e-853e72a4f972","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/data-upload/status","description":"<p><strong>Local, this PC only</strong> · <code>GET {{baseUrl}}/api/v1/data-upload/status</code> · Bearer (collection auth) · Read only — nothing is sent</p>\n<hr />\n<p>The Cloud data upload service's state: <code>state</code>, <code>enabled</code>, <code>paused</code>, <code>uploadOrigin</code> (<code>unconfigured</code> / <code>development-local</code> / <code>pinned-upload</code>), <code>activity</code> (company, year, table, phase) or null, <code>manualRunQueued</code>, <code>nextDueUtc</code>, <code>openJobs</code>, <code>waitingJobs</code>, <code>serverUnavailableUntilUtc</code>, <code>serverLimits</code>, plan eligibility. From the LAN: <code>403 DATA_UPLOAD_LOOPBACK_ONLY</code> before the token is read. Never relayed.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5z.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","data-upload","status"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"de3f7033-c7ac-5a8e-cf1d-08e9f9d1e5b4","name":"200 – idle, enabled (synthetic)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/data-upload/status","description":"**Local, this PC only** · `GET {{baseUrl}}/api/v1/data-upload/status` · Bearer (collection auth) · Read only — nothing is sent\n\n---\n\nThe Cloud data upload service's state: `state`, `enabled`, `paused`, `uploadOrigin` (`unconfigured` / `development-local` / `pinned-upload`), `activity` (company, year, table, phase) or null, `manualRunQueued`, `nextDueUtc`, `openJobs`, `waitingJobs`, `serverUnavailableUntilUtc`, `serverLimits`, plan eligibility. From the LAN: `403 DATA_UPLOAD_LOOPBACK_ONLY` before the token is read. Never relayed.\n\nContract: `docs/LOCAL-API.md` section 5z."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"94f285a6b7c8d9e0f1a2b3c4d5e6f708"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"state\": \"idle\",\n    \"enabled\": true,\n    \"paused\": false,\n    \"uploadOrigin\": \"pinned-upload\",\n    \"activity\": null,\n    \"manualRunQueued\": false,\n    \"nextDueUtc\": \"2026-10-18T06:15:00Z\",\n    \"openJobs\": 0,\n    \"waitingJobs\": 0,\n    \"serverUnavailableUntilUtc\": null,\n    \"serverLimits\": { \"protocol\": 3, \"chunkBytes\": 16777216 }\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"11ae5c8e-671d-00d3-989e-853e72a4f972"},{"name":"Cloud data upload – tables","id":"215d0108-bd94-6630-f2de-82d7e236fb19","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/data-upload/tables","description":"<p><strong>Local, this PC only</strong> · <code>GET {{baseUrl}}/api/v1/data-upload/tables</code> · Bearer (collection auth) · Read only</p>\n<hr />\n<p>One row per configured company × allowed year × catalog table: <code>companyCode</code>, <code>financialYear</code>, <code>table</code>, <code>state</code> (the open job's state, else the last outcome, a refusal such as <code>UPLOAD_PLAN_LIMIT</code> / <code>UPLOAD_COMPANY_DISABLED</code> / <code>UPLOAD_YEAR_NOT_ALLOWED</code>, or <code>pending</code>), <code>rows</code>, <code>databaseBytes</code>, <code>zipBytes</code>, <code>publishedVersion</code>, <code>publishedUtc</code>, <code>lastCheckedUtc</code>, <code>nextDueUtc</code>, <code>uploadId</code>, chunk progress. LAN: <code>403 DATA_UPLOAD_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5z.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","data-upload","tables"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"d4245ed3-631b-54f9-caf4-780b284d7169","name":"200 – two tables (synthetic)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/data-upload/tables","description":"**Local, this PC only** · `GET {{baseUrl}}/api/v1/data-upload/tables` · Bearer (collection auth) · Read only\n\n---\n\nOne row per configured company × allowed year × catalog table: `companyCode`, `financialYear`, `table`, `state` (the open job's state, else the last outcome, a refusal such as `UPLOAD_PLAN_LIMIT` / `UPLOAD_COMPANY_DISABLED` / `UPLOAD_YEAR_NOT_ALLOWED`, or `pending`), `rows`, `databaseBytes`, `zipBytes`, `publishedVersion`, `publishedUtc`, `lastCheckedUtc`, `nextDueUtc`, `uploadId`, chunk progress. LAN: `403 DATA_UPLOAD_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5z."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"a50396b7c8d9e0f1a2b3c4d5e6f70819"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    { \"companyCode\": \"COMP0002\", \"financialYear\": \"2026\", \"table\": \"Master1\", \"state\": \"published\", \"rows\": 1500, \"databaseBytes\": 2097152, \"zipBytes\": 524288, \"publishedVersion\": 4, \"publishedUtc\": \"2026-10-18T05:30:00Z\", \"lastCheckedUtc\": \"2026-10-18T06:00:00Z\", \"nextDueUtc\": \"2026-10-18T06:15:00Z\", \"uploadId\": null },\n    { \"companyCode\": \"COMP0002\", \"financialYear\": \"2026\", \"table\": \"Tran2\", \"state\": \"pending\", \"rows\": null, \"databaseBytes\": null, \"zipBytes\": null, \"publishedVersion\": null, \"publishedUtc\": null, \"lastCheckedUtc\": null, \"nextDueUtc\": \"2026-10-18T06:30:00Z\", \"uploadId\": null }\n  ],\n  \"metadata\": {}\n}"}],"_postman_id":"215d0108-bd94-6630-f2de-82d7e236fb19"},{"name":"Cloud data upload – settings","id":"f2158af5-6901-645d-56e7-e24538c5f58a","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/data-upload/settings","description":"<p><strong>Local, this PC only</strong> · <code>GET {{baseUrl}}/api/v1/data-upload/settings</code> · Bearer (collection auth) · Read only</p>\n<hr />\n<p>The saved upload settings: <code>enabled</code> (the per-PC switch, off by default), <code>paused</code>, <code>currentLightMinutes</code>, <code>currentHeavyMinutes</code>, <code>historicalAfterLocalHour</code>. Change them only with '⚠⚠ Cloud data upload – change settings'. LAN: <code>403 DATA_UPLOAD_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5z.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","data-upload","settings"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"c9cf641c-a462-e4a1-edfd-7d376a696d1e","name":"200 – the default cadence (synthetic)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/data-upload/settings","description":"**Local, this PC only** · `GET {{baseUrl}}/api/v1/data-upload/settings` · Bearer (collection auth) · Read only\n\n---\n\nThe saved upload settings: `enabled` (the per-PC switch, off by default), `paused`, `currentLightMinutes`, `currentHeavyMinutes`, `historicalAfterLocalHour`. Change them only with '⚠⚠ Cloud data upload – change settings'. LAN: `403 DATA_UPLOAD_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5z."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"b614a7c8d9e0f1a2b3c4d5e6f708192a"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"enabled\": false, \"paused\": false, \"currentLightMinutes\": 15, \"currentHeavyMinutes\": 30, \"historicalAfterLocalHour\": 1 },\n  \"metadata\": {}\n}"}],"_postman_id":"f2158af5-6901-645d-56e7-e24538c5f58a"},{"name":"Google connection – status","id":"5d038b18-43e5-9f7e-817e-e1b65b2b8b7c","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/google/connection","description":"<p><strong>Local, this PC only</strong> · <code>GET {{baseUrl}}/api/v1/google/connection</code> · Bearer (collection auth) · Read only</p>\n<hr />\n<p>The Google connection as this PC sees it: <code>state</code> (<code>unavailable</code>, <code>not_signed_in</code>, <code>waiting</code>, <code>confirm</code>, <code>connected</code>, <code>access_not_allowed</code>, <code>cloud_unreachable</code>, <code>other_device</code>), the account, scopes and the connection id (<code>gcn_…</code>) when there is one. <strong>Never a Google token, client secret, authorization URL or <code>state</code>.</strong> From the LAN: <code>403 GOOGLE_LOOPBACK_ONLY</code> before the token is read (OD-G6). Never relayed.</p>\n<p>Keep <code>refresh</code> disabled for a no-cloud read. Contract: <code>docs/LOCAL-API.md</code> section 5v.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","connection"],"host":["{{baseUrl}}"],"query":[{"disabled":true,"description":{"content":"<p>true = ask the AI Zeny cloud now (one cloud call); default = the snapshot (refreshed in the background when older than 60 s)</p>\n","type":"text/plain"},"key":"refresh","value":"true"}],"variable":[]}},"response":[{"id":"d065183c-9dde-56f1-c999-1df4c53b8e89","name":"200 – connected (synthetic account)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{baseUrl}}/api/v1/google/connection","host":["{{baseUrl}}"],"path":["api","v1","google","connection"],"query":[{"key":"refresh","value":"true","description":"true = ask the AI Zeny cloud now (one cloud call); default = the snapshot (refreshed in the background when older than 60 s)","disabled":true}]},"description":"**Local, this PC only** · `GET {{baseUrl}}/api/v1/google/connection` · Bearer (collection auth) · Read only\n\n---\n\nThe Google connection as this PC sees it: `state` (`unavailable`, `not_signed_in`, `waiting`, `confirm`, `connected`, `access_not_allowed`, `cloud_unreachable`, `other_device`), the account, scopes and the connection id (`gcn_…`) when there is one. **Never a Google token, client secret, authorization URL or `state`.** From the LAN: `403 GOOGLE_LOOPBACK_ONLY` before the token is read (OD-G6). Never relayed.\n\nKeep `refresh` disabled for a no-cloud read. Contract: `docs/LOCAL-API.md` section 5v."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"c725b8d9e0f1a2b3c4d5e6f708192a3b","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"state\": \"connected\",\n    \"connectionId\": \"gcn_00000000000000000000000000\",\n    \"account\": { \"email\": \"owner@example.com\", \"name\": \"Example Owner\" },\n    \"scopes\": [\"drive.file\", \"spreadsheets\", \"openid\", \"email\"],\n    \"lastCheckedUtc\": \"2026-10-18T06:00:00Z\"\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"5d038b18-43e5-9f7e-817e-e1b65b2b8b7c"},{"name":"Sheets exports – list","id":"54a1610d-9d9b-ddc6-4503-ad69d5473dcb","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/google/exports","description":"<p><strong>Local, this PC only</strong> · <code>GET {{baseUrl}}/api/v1/google/exports</code> · Bearer (collection auth) · Read only — no Google call</p>\n<hr />\n<p>Every Google Sheets export saved on this PC: <code>name</code>, <code>source</code> (<code>{ kind: \"operation\" | \"savedQuery\", operation | queryName, companyCode, financialYear, request | parameters, script }</code>), <code>rowsPath</code>, <code>columns</code>, <code>destination</code> (<code>spreadsheetId</code>, <code>spreadsheetTitle</code>, <code>sheetId</code>, <code>sheetTitle</code>, <code>googleAccount</code>, <code>takeoverConfirmedUtc</code>, <code>takeoverFromJob</code>), <code>intervalMinutes</code>, <code>paused</code>, <code>revision</code>, times, <code>status</code> = <code>{ state (\"running\" | \"scheduled\" | \"paused\" | \"waiting_for_account\" | \"needs_attention\"), attention, connectedAccount, active, latest, lastSucceeded, nextRunUtc, retryUtc }</code> and <code>notes</code>. Sets <code>googleExportName</code> from the first export when it is empty. LAN: <code>403 GOOGLE_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5x.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","exports"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"6b31c13e-3977-8297-8eac-88a6f19ecf24","name":"200 – one scheduled export (synthetic)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/google/exports","description":"**Local, this PC only** · `GET {{baseUrl}}/api/v1/google/exports` · Bearer (collection auth) · Read only — no Google call\n\n---\n\nEvery Google Sheets export saved on this PC: `name`, `source` (`{ kind: \"operation\" | \"savedQuery\", operation | queryName, companyCode, financialYear, request | parameters, script }`), `rowsPath`, `columns`, `destination` (`spreadsheetId`, `spreadsheetTitle`, `sheetId`, `sheetTitle`, `googleAccount`, `takeoverConfirmedUtc`, `takeoverFromJob`), `intervalMinutes`, `paused`, `revision`, times, `status` = `{ state (\"running\" | \"scheduled\" | \"paused\" | \"waiting_for_account\" | \"needs_attention\"), attention, connectedAccount, active, latest, lastSucceeded, nextRunUtc, retryUtc }` and `notes`. Sets `googleExportName` from the first export when it is empty. LAN: `403 GOOGLE_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5x."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"d836c9e0f1a2b3c4d5e6f708192a3b4c","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    {\n      \"name\": \"Units to Sheet\",\n      \"source\": { \"kind\": \"operation\", \"operation\": \"busy.units.query\", \"queryName\": null, \"companyCode\": \"COMP0002\", \"financialYear\": \"2026\", \"request\": {}, \"parameters\": null, \"script\": null },\n      \"rowsPath\": null,\n      \"columns\": null,\n      \"destination\": { \"spreadsheetId\": \"1AbCdEfGhIjKlMnOpQrStUvWxYz0123456789\", \"spreadsheetTitle\": \"Example export\", \"sheetId\": 0, \"sheetTitle\": \"Units\", \"googleAccount\": \"owner@example.com\", \"takeoverConfirmedUtc\": null, \"takeoverFromJob\": null },\n      \"intervalMinutes\": 60,\n      \"paused\": false,\n      \"revision\": 2,\n      \"createdUtc\": \"2026-10-02T09:00:00Z\",\n      \"updatedUtc\": \"2026-10-02T09:30:00Z\",\n      \"status\": { \"state\": \"scheduled\", \"attention\": null, \"connectedAccount\": true, \"active\": null, \"latest\": { \"status\": \"succeeded\", \"finishedUtc\": \"2026-10-18T05:30:05Z\" }, \"lastSucceeded\": \"2026-10-18T05:30:05Z\", \"nextRunUtc\": \"2026-10-18T06:30:00Z\", \"retryUtc\": null },\n      \"notes\": []\n    }\n  ],\n  \"metadata\": {}\n}"}],"_postman_id":"54a1610d-9d9b-ddc6-4503-ad69d5473dcb"},{"name":"Sheets export – view","id":"ce2bab05-93a0-9e94-ccc4-94d36f834abe","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}","description":"<p><strong>Local, this PC only</strong> · <code>GET {{baseUrl}}/api/v1/google/exports/{{googleExportName}}</code> · Bearer (collection auth) · Read only — no Google call</p>\n<hr />\n<p>One export as in the list; sets <code>googleExportRevision</code>. <code>404 SHEET_EXPORT_NOT_FOUND</code> for an unknown name. Skipped while <code>googleExportName</code> is empty (run 'Sheets exports – list' first). LAN: <code>403 GOOGLE_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5x.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","exports","{{googleExportName}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"77adfb14-6178-51bc-ae36-3baa93c6885e","name":"404 – no export with that name (synthetic)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}","description":"**Local, this PC only** · `GET {{baseUrl}}/api/v1/google/exports/{{googleExportName}}` · Bearer (collection auth) · Read only — no Google call\n\n---\n\nOne export as in the list; sets `googleExportRevision`. `404 SHEET_EXPORT_NOT_FOUND` for an unknown name. Skipped while `googleExportName` is empty (run 'Sheets exports – list' first). LAN: `403 GOOGLE_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5x."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"e947d0f1a2b3c4d5e6f708192a3b4c5d"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": { \"code\": \"SHEET_EXPORT_NOT_FOUND\", \"message\": \"There is no Sheets export with that name.\", \"field\": \"name\" },\n    \"requestId\": \"e947d0f1a2b3c4d5e6f708192a3b4c5d\"\n  }\n}"}],"_postman_id":"ce2bab05-93a0-9e94-ccc4-94d36f834abe"},{"name":"Sheets export – run history","id":"1ce1e143-5e98-8dac-9a16-eab7c3f7a883","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}/runs?page=1&pageSize=50","description":"<p><strong>Local, this PC only</strong> · <code>GET {{baseUrl}}/api/v1/google/exports/{{googleExportName}}/runs</code> · Bearer (collection auth) · Read only</p>\n<hr />\n<p>One export's runs, newest first: <code>{ runs, page, pageSize, total }</code>; each run has <code>trigger</code>, <code>status</code> (<code>queued</code>, <code>running</code>, <code>succeeded</code>, <code>failed</code>, <code>cancelled</code>, <code>interrupted</code>, <code>uncertain</code>), <code>stage</code>, counts and times — never sheet contents or rows. Skipped while <code>googleExportName</code> is empty. LAN: <code>403 GOOGLE_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5x.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","exports","{{googleExportName}}","runs"],"host":["{{baseUrl}}"],"query":[{"key":"page","value":"1"},{"description":{"content":"<p>1 to 100</p>\n","type":"text/plain"},"key":"pageSize","value":"50"}],"variable":[]}},"response":[{"id":"8f2d68b5-2e35-214f-1b67-56090ea7db7f","name":"200 – one export's runs (synthetic)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}/runs?page=1&pageSize=50","host":["{{baseUrl}}"],"path":["api","v1","google","exports","{{googleExportName}}","runs"],"query":[{"key":"page","value":"1"},{"key":"pageSize","description":"1 to 100","value":"50"}]},"description":"**Local, this PC only** · `GET {{baseUrl}}/api/v1/google/exports/{{googleExportName}}/runs` · Bearer (collection auth) · Read only\n\n---\n\nOne export's runs, newest first: `{ runs, page, pageSize, total }`; each run has `trigger`, `status` (`queued`, `running`, `succeeded`, `failed`, `cancelled`, `interrupted`, `uncertain`), `stage`, counts and times — never sheet contents or rows. Skipped while `googleExportName` is empty. LAN: `403 GOOGLE_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5x."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"fa58e1a2b3c4d5e6f708192a3b4c5d6e","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"runs\": [\n      { \"id\": 42, \"export\": \"Units to Sheet\", \"trigger\": \"scheduled\", \"status\": \"succeeded\", \"stage\": \"cleanup\", \"rows\": 8, \"columns\": 5, \"startedUtc\": \"2026-10-18T05:30:00Z\", \"finishedUtc\": \"2026-10-18T05:30:05Z\", \"errorCode\": null }\n    ],\n    \"page\": 1,\n    \"pageSize\": 50,\n    \"total\": 1\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"1ce1e143-5e98-8dac-9a16-eab7c3f7a883"},{"name":"Sheets exports – all runs","id":"b6cf8d92-2b3e-b898-f52d-24b4ff6d9ffe","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/google/export-runs?page=1&pageSize=50","description":"<p><strong>Local, this PC only</strong> · <code>GET {{baseUrl}}/api/v1/google/export-runs</code> · Bearer (collection auth) · Read only</p>\n<hr />\n<p>Every export's runs, newest first, as <code>{ runs, page, pageSize, total }</code>. Run history is kept in <code>runtime.db</code> and is intentionally not restored by a backup. LAN: <code>403 GOOGLE_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5x.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","export-runs"],"host":["{{baseUrl}}"],"query":[{"key":"page","value":"1"},{"description":{"content":"<p>1 to 100</p>\n","type":"text/plain"},"key":"pageSize","value":"50"}],"variable":[]}},"response":[{"id":"3737d98d-0ed5-2753-c22b-77d55a68e16a","name":"200 – every export's runs (synthetic)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{baseUrl}}/api/v1/google/export-runs?page=1&pageSize=50","host":["{{baseUrl}}"],"path":["api","v1","google","export-runs"],"query":[{"key":"page","value":"1"},{"key":"pageSize","value":"50","description":"1 to 100"}]},"description":"**Local, this PC only** · `GET {{baseUrl}}/api/v1/google/export-runs` · Bearer (collection auth) · Read only\n\n---\n\nEvery export's runs, newest first, as `{ runs, page, pageSize, total }`. Run history is kept in `runtime.db` and is intentionally not restored by a backup. LAN: `403 GOOGLE_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5x."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"0b69f2b3c4d5e6f708192a3b4c5d6e7f","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"runs\": [\n      { \"id\": 43, \"export\": \"Customers to Sheet\", \"trigger\": \"manual\", \"status\": \"failed\", \"stage\": \"upload\", \"rows\": null, \"columns\": null, \"startedUtc\": \"2026-10-18T05:40:00Z\", \"finishedUtc\": \"2026-10-18T05:40:03Z\", \"errorCode\": \"GOOGLE_RATE_LIMITED\" },\n      { \"id\": 42, \"export\": \"Units to Sheet\", \"trigger\": \"scheduled\", \"status\": \"succeeded\", \"stage\": \"cleanup\", \"rows\": 8, \"columns\": 5, \"startedUtc\": \"2026-10-18T05:30:00Z\", \"finishedUtc\": \"2026-10-18T05:30:05Z\", \"errorCode\": null }\n    ],\n    \"page\": 1,\n    \"pageSize\": 50,\n    \"total\": 2\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"b6cf8d92-2b3e-b898-f52d-24b4ff6d9ffe"},{"name":"Backup – status","id":"06963c39-1668-b0cd-1f2d-81be3923ebd9","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/backup","description":"<p><strong>Local, this PC only</strong> · <code>GET {{baseUrl}}/api/v1/backup</code> · Bearer (collection auth) · Read only — no Drive call</p>\n<hr />\n<p>Google Drive backup status: settings (<code>enabled</code>, <code>dailyAt</code>, time zone, folder), the recovery key's <strong>status only</strong> (never the key), the Google state and account, the running backup (stage, percent), last verified backup, last failure, the next run (daily / catch-up / retry / off) and pending cloud registrations. From the LAN: <code>403 BACKUP_LOOPBACK_ONLY</code>. Never relayed.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5w.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","backup"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"9297dd92-8119-4c96-1099-ae23ef6aa4df","name":"200 – daily backup on, key saved (synthetic)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/backup","description":"**Local, this PC only** · `GET {{baseUrl}}/api/v1/backup` · Bearer (collection auth) · Read only — no Drive call\n\n---\n\nGoogle Drive backup status: settings (`enabled`, `dailyAt`, time zone, folder), the recovery key's **status only** (never the key), the Google state and account, the running backup (stage, percent), last verified backup, last failure, the next run (daily / catch-up / retry / off) and pending cloud registrations. From the LAN: `403 BACKUP_LOOPBACK_ONLY`. Never relayed.\n\nContract: `docs/LOCAL-API.md` section 5w."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"1c7a03c4d5e6f708192a3b4c5d6e7f80","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"settings\": { \"enabled\": true, \"dailyAt\": \"02:00\", \"timeZone\": \"Asia/Kolkata\", \"folder\": \"AI Zeny Backups\" },\n    \"recoveryKey\": { \"status\": \"saved\", \"keyId\": \"rk_00000000\" },\n    \"google\": { \"state\": \"connected\", \"account\": \"owner@example.com\" },\n    \"running\": null,\n    \"lastVerified\": { \"utc\": \"2026-10-18T02:00:40Z\", \"bytes\": 81920 },\n    \"lastFailure\": null,\n    \"nextRun\": { \"kind\": \"daily\", \"utc\": \"2026-10-19T02:00:00Z\" },\n    \"pendingRegistrations\": 0\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"06963c39-1668-b0cd-1f2d-81be3923ebd9"},{"name":"Backup – run history","id":"e169b65d-a2d4-61f8-b872-548773764cb6","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/backup/runs?page=1&pageSize=50","description":"<p><strong>Local, this PC only</strong> · <code>GET {{baseUrl}}/api/v1/backup/runs</code> · Bearer (collection auth) · Read only</p>\n<hr />\n<p>Backup runs, newest first (1-200 a page): trigger (daily, catch-up, retry, manual), status, stage, sizes and times — never archive contents or the key. LAN: <code>403 BACKUP_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5w.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","backup","runs"],"host":["{{baseUrl}}"],"query":[{"key":"page","value":"1"},{"description":{"content":"<p>1 to 200</p>\n","type":"text/plain"},"key":"pageSize","value":"50"}],"variable":[]}},"response":[{"id":"7d15f364-6d4b-09b9-eda0-67aceb0273fc","name":"200 – backup runs (synthetic)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{baseUrl}}/api/v1/backup/runs?page=1&pageSize=50","host":["{{baseUrl}}"],"path":["api","v1","backup","runs"],"query":[{"value":"1","key":"page"},{"value":"50","description":"1 to 200","key":"pageSize"}]},"description":"**Local, this PC only** · `GET {{baseUrl}}/api/v1/backup/runs` · Bearer (collection auth) · Read only\n\n---\n\nBackup runs, newest first (1-200 a page): trigger (daily, catch-up, retry, manual), status, stage, sizes and times — never archive contents or the key. LAN: `403 BACKUP_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5w."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"2d8b14d5e6f708192a3b4c5d6e7f8091","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    { \"id\": 7, \"trigger\": \"daily\", \"status\": \"succeeded\", \"stage\": \"registered\", \"bytes\": 81920, \"startedUtc\": \"2026-10-18T02:00:00Z\", \"finishedUtc\": \"2026-10-18T02:00:40Z\", \"errorCode\": null }\n  ],\n  \"metadata\": { \"page\": 1, \"pageSize\": 50, \"total\": 1 }\n}"}],"_postman_id":"e169b65d-a2d4-61f8-b872-548773764cb6"}],"id":"044020f4-d004-e454-500c-b1454c4b70ec","_postman_id":"044020f4-d004-e454-500c-b1454c4b70ec","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ Cloud Data Upload — sends BUSY data to the upload server (this PC only)","item":[{"name":"⚠⚠ Cloud data upload – run now (uploads BUSY data)","id":"09bced3c-5196-8e5d-99fe-88543e666fe0","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"table\": \"Master1\",\n  \"force\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/data-upload/run","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/data-upload/run</code> · Bearer (collection auth) · <strong>HIGH IMPACT: sends the customer's BUSY tables to the upload server</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Do not run without the owner's approval.</strong> Queues one manual upload cycle: the named tables (all when members are left out) are read from BUSY (read only), packed as SQLite snapshots and uploaded to the pinned upload server. Body <code>{ companyCode?, financialYear?, table?, force? }</code>; a manual run never re-sends a table within 10 minutes of its last publication or one with an open job; <code>force: true</code> uploads unchanged content too. Answer <code>{ queued: true }</code>; watch 'Cloud data upload – status'. Refusals: <code>409 DATA_UPLOAD_NOT_AVAILABLE</code> (not configured, not enrolled, access not allowed, switched off or paused), <code>409 DATA_UPLOAD_RUN_ACTIVE</code>, <code>400 DATA_UPLOAD_INVALID</code>, <code>403 PLAN_FEATURE_NOT_INCLUDED</code> / <code>UPLOAD_NOT_IN_PLAN</code> (Plus), <code>403 DATA_UPLOAD_LOOPBACK_ONLY</code> (LAN).</p>\n<p><strong>Effect:</strong> customer data leaves the PC. <strong>Recovery:</strong> pause ('⚠ Cloud data upload – pause'); published versions stay on the server (server-side removal is the server owner's task). Run guard: <code>confirmMutating = yes</code> and <code>confirmHighImpact = POST /api/v1/data-upload/run</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5z; <code>docs/features/BUSY-Data-Upload-Blueprint.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","data-upload","run"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"4fae05b0-f5cf-4540-6314-fdc71baa9e58","name":"409 – upload switched off or paused: nothing sent (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"table\": \"Master1\",\n  \"force\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/data-upload/run","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/data-upload/run` · Bearer (collection auth) · **HIGH IMPACT: sends the customer's BUSY tables to the upload server** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Do not run without the owner's approval.** Queues one manual upload cycle: the named tables (all when members are left out) are read from BUSY (read only), packed as SQLite snapshots and uploaded to the pinned upload server. Body `{ companyCode?, financialYear?, table?, force? }`; a manual run never re-sends a table within 10 minutes of its last publication or one with an open job; `force: true` uploads unchanged content too. Answer `{ queued: true }`; watch 'Cloud data upload – status'. Refusals: `409 DATA_UPLOAD_NOT_AVAILABLE` (not configured, not enrolled, access not allowed, switched off or paused), `409 DATA_UPLOAD_RUN_ACTIVE`, `400 DATA_UPLOAD_INVALID`, `403 PLAN_FEATURE_NOT_INCLUDED` / `UPLOAD_NOT_IN_PLAN` (Plus), `403 DATA_UPLOAD_LOOPBACK_ONLY` (LAN).\n\n**Effect:** customer data leaves the PC. **Recovery:** pause ('⚠ Cloud data upload – pause'); published versions stay on the server (server-side removal is the server owner's task). Run guard: `confirmMutating = yes` and `confirmHighImpact = POST /api/v1/data-upload/run`.\n\nContract: `docs/LOCAL-API.md` section 5z; `docs/features/BUSY-Data-Upload-Blueprint.md`."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"3e9c25e6f708192a3b4c5d6e7f8091a2"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": { \"code\": \"DATA_UPLOAD_NOT_AVAILABLE\", \"message\": \"Cloud data upload is switched off or paused on this PC.\" },\n    \"requestId\": \"3e9c25e6f708192a3b4c5d6e7f8091a2\"\n  }\n}"}],"_postman_id":"09bced3c-5196-8e5d-99fe-88543e666fe0"},{"name":"⚠ Cloud data upload – pause","id":"225abc45-736d-6f9f-e2fa-bc0232e632ec","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/data-upload/pause","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/data-upload/pause</code> · Bearer (collection auth) · <strong>Changes AI Zeny on the PC</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Pauses automatic uploads; a running cycle stops after its current table; kept across restarts. No body. Answer: the settings (<code>paused: true</code>). Nothing is deleted locally or on the server. <strong>Undo:</strong> '⚠ Cloud data upload – resume'. LAN: <code>403 DATA_UPLOAD_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5z.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","data-upload","pause"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"5d261b5a-e98a-691f-b499-394cc6933937","name":"200 – paused (synthetic)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/data-upload/pause","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/data-upload/pause` · Bearer (collection auth) · **Changes AI Zeny on the PC** (guarded by `confirmMutating`)\n\n---\n\n**Mutating — run manually.** Pauses automatic uploads; a running cycle stops after its current table; kept across restarts. No body. Answer: the settings (`paused: true`). Nothing is deleted locally or on the server. **Undo:** '⚠ Cloud data upload – resume'. LAN: `403 DATA_UPLOAD_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5z."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"4fad36f708192a3b4c5d6e7f8091a2b3"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"enabled\": true, \"paused\": true, \"currentLightMinutes\": 15, \"currentHeavyMinutes\": 30, \"historicalAfterLocalHour\": 1 },\n  \"metadata\": {}\n}"}],"_postman_id":"225abc45-736d-6f9f-e2fa-bc0232e632ec"},{"name":"⚠ Cloud data upload – resume","id":"918eeadc-9be6-83b3-183b-4618e1c26af3","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/data-upload/resume","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/data-upload/resume</code> · Bearer (collection auth) · <strong>Changes AI Zeny on the PC</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Resumes automatic uploads; with the switch on, the next scheduled cycle <strong>uploads changed tables</strong>. No body. Answer: the settings (<code>paused: false</code>). Known client finding (2026-10-07): a Run now right after Resume can answer <code>409</code> while the Resume-triggered cycle runs. LAN: <code>403 DATA_UPLOAD_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5z.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","data-upload","resume"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"26a9ce0d-1dd8-2d02-910c-bb506615f2c7","name":"200 – resumed (synthetic)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/data-upload/resume","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/data-upload/resume` · Bearer (collection auth) · **Changes AI Zeny on the PC** (guarded by `confirmMutating`)\n\n---\n\n**Mutating — run manually.** Resumes automatic uploads; with the switch on, the next scheduled cycle **uploads changed tables**. No body. Answer: the settings (`paused: false`). Known client finding (2026-10-07): a Run now right after Resume can answer `409` while the Resume-triggered cycle runs. LAN: `403 DATA_UPLOAD_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5z."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"50be4708192a3b4c5d6e7f8091a2b3c4"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"enabled\": true, \"paused\": false, \"currentLightMinutes\": 15, \"currentHeavyMinutes\": 30, \"historicalAfterLocalHour\": 1 },\n  \"metadata\": {}\n}"}],"_postman_id":"918eeadc-9be6-83b3-183b-4618e1c26af3"},{"name":"⚠⚠ Cloud data upload – change settings (switch on/off, cadence)","id":"35dd0fbf-fcee-d253-8877-f92a81fa593b","request":{"method":"PUT","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"currentLightMinutes\": 15,\n  \"currentHeavyMinutes\": 30,\n  \"historicalAfterLocalHour\": 1\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/data-upload/settings","description":"<p><strong>Local, this PC only</strong> · <code>PUT {{baseUrl}}/api/v1/data-upload/settings</code> · Bearer (collection auth) · <strong>HIGH IMPACT when <code>enabled</code> is sent</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Do not run without the owner's approval.</strong> Body <code>{ enabled?, currentLightMinutes?, currentHeavyMinutes?, historicalAfterLocalHour? }</code> — a member left out keeps its value. The sample sends only the owner-approved default cadence and <strong>leaves <code>enabled</code> out</strong>; <code>enabled: true</code> starts automatic uploads of BUSY data, <code>enabled: false</code> stops them (the saved switch is never changed by plan eligibility). Answer: the settings. Refusals <code>400 BAD_REQUEST</code> (<code>field</code>), <code>403 DATA_UPLOAD_LOOPBACK_ONLY</code>.</p>\n<p><strong>Recovery:</strong> send the previous values again (read 'Cloud data upload – settings' first). Run guard: <code>confirmMutating = yes</code> and <code>confirmHighImpact = PUT /api/v1/data-upload/settings</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5z.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","data-upload","settings"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"20e87e58-7448-27c7-800d-38fd4461db3e","name":"200 – cadence saved, switch unchanged (synthetic)","originalRequest":{"method":"PUT","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"currentLightMinutes\": 15,\n  \"currentHeavyMinutes\": 30,\n  \"historicalAfterLocalHour\": 1\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/data-upload/settings","description":"**Local, this PC only** · `PUT {{baseUrl}}/api/v1/data-upload/settings` · Bearer (collection auth) · **HIGH IMPACT when `enabled` is sent** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Do not run without the owner's approval.** Body `{ enabled?, currentLightMinutes?, currentHeavyMinutes?, historicalAfterLocalHour? }` — a member left out keeps its value. The sample sends only the owner-approved default cadence and **leaves `enabled` out**; `enabled: true` starts automatic uploads of BUSY data, `enabled: false` stops them (the saved switch is never changed by plan eligibility). Answer: the settings. Refusals `400 BAD_REQUEST` (`field`), `403 DATA_UPLOAD_LOOPBACK_ONLY`.\n\n**Recovery:** send the previous values again (read 'Cloud data upload – settings' first). Run guard: `confirmMutating = yes` and `confirmHighImpact = PUT /api/v1/data-upload/settings`.\n\nContract: `docs/LOCAL-API.md` section 5z."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"61cf58192a3b4c5d6e7f8091a2b3c4d5","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"enabled\": false, \"paused\": false, \"currentLightMinutes\": 15, \"currentHeavyMinutes\": 30, \"historicalAfterLocalHour\": 1 },\n  \"metadata\": {}\n}"}],"_postman_id":"35dd0fbf-fcee-d253-8877-f92a81fa593b"}],"id":"5d9a3594-9db5-d798-45fe-034d0eeee894","_postman_id":"5d9a3594-9db5-d798-45fe-034d0eeee894","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ Google — sign-in, Sheets exports & spreadsheets (external; this PC only)","item":[{"name":"⚠ Google sign-in – start an attempt","id":"dc90e5d0-64c7-4491-efea-b3e0e8755065","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"purpose\": \"connect\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/connection/attempts","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/google/connection/attempts</code> · Bearer (collection auth) · <strong>External: asks the AI Zeny cloud to open a Google sign-in</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Mutating — run manually; normally the AI Zeny window does this</strong> (Google Sheets → Sign in to Google). Body empty or <code>{ \"purpose\": \"connect\" | \"reconnect\" }</code>. Answer <code>{ attemptId, authorizationUrl, expiresUtc, pollAfterMs }</code>: the <code>authorizationUrl</code> (checked to be <code>https://accounts.google.com/o/oauth2/v2/auth?…</code> only) must be opened in the system browser <strong>once</strong>; it is not stored or logged. Nothing about the current connection changes until '⚠⚠ Google connection – confirm'. <strong>Undo:</strong> '⚠ Google sign-in – cancel the attempt'. LAN: <code>403 GOOGLE_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5v.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","connection","attempts"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"f43e40e9-7259-57ef-cffe-9db3f7e67bc4","name":"200 – attempt opened (synthetic; open the URL once)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"purpose\": \"connect\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/connection/attempts","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/google/connection/attempts` · Bearer (collection auth) · **External: asks the AI Zeny cloud to open a Google sign-in** (guarded by `confirmMutating`)\n\n---\n\n**Mutating — run manually; normally the AI Zeny window does this** (Google Sheets → Sign in to Google). Body empty or `{ \"purpose\": \"connect\" | \"reconnect\" }`. Answer `{ attemptId, authorizationUrl, expiresUtc, pollAfterMs }`: the `authorizationUrl` (checked to be `https://accounts.google.com/o/oauth2/v2/auth?…` only) must be opened in the system browser **once**; it is not stored or logged. Nothing about the current connection changes until '⚠⚠ Google connection – confirm'. **Undo:** '⚠ Google sign-in – cancel the attempt'. LAN: `403 GOOGLE_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5v."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"72d0692a3b4c5d6e7f8091a2b3c4d5e6"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"attemptId\": \"gst_00000000000000000000000000\",\n    \"authorizationUrl\": \"https://accounts.google.com/o/oauth2/v2/auth?client_id=EXAMPLE&state=EXAMPLE\",\n    \"expiresUtc\": \"2026-10-18T06:20:00Z\",\n    \"pollAfterMs\": 3000\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"dc90e5d0-64c7-4491-efea-b3e0e8755065"},{"name":"Google sign-in – attempt status","id":"271ff269-8d19-96ca-1491-ef74b3c217ce","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/google/connection/attempts/{{googleAttemptId}}","description":"<p><strong>Local, this PC only</strong> · <code>GET {{baseUrl}}/api/v1/google/connection/attempts/{{googleAttemptId}}</code> · Bearer (collection auth) · Read only (no state change)</p>\n<hr />\n<p><code>{ attemptId, status, failureCode, expiresUtc, connection, cloudReachable }</code> for this Host's attempt; <code>404 GOOGLE_ATTEMPT_NOT_FOUND</code> otherwise. Poll after <code>pollAfterMs</code> (3 s, then 5 s). Skipped while <code>googleAttemptId</code> is empty. LAN: <code>403 GOOGLE_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5v.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","connection","attempts","{{googleAttemptId}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"00310b1a-fd03-e63e-1693-93c6482725ed","name":"404 – not this Host's attempt (synthetic)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/google/connection/attempts/{{googleAttemptId}}","description":"**Local, this PC only** · `GET {{baseUrl}}/api/v1/google/connection/attempts/{{googleAttemptId}}` · Bearer (collection auth) · Read only (no state change)\n\n---\n\n`{ attemptId, status, failureCode, expiresUtc, connection, cloudReachable }` for this Host's attempt; `404 GOOGLE_ATTEMPT_NOT_FOUND` otherwise. Poll after `pollAfterMs` (3 s, then 5 s). Skipped while `googleAttemptId` is empty. LAN: `403 GOOGLE_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5v."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"83e17a3b4c5d6e7f8091a2b3c4d5e6f7","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": { \"code\": \"GOOGLE_ATTEMPT_NOT_FOUND\", \"message\": \"There is no such sign-in attempt on this PC.\" },\n    \"requestId\": \"83e17a3b4c5d6e7f8091a2b3c4d5e6f7\"\n  }\n}"}],"_postman_id":"271ff269-8d19-96ca-1491-ef74b3c217ce"},{"name":"⚠ Google sign-in – cancel the attempt","id":"95605ff8-3121-c4ca-7963-68f3cb4b4253","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/google/connection/attempts/{{googleAttemptId}}/cancel","description":"<p><strong>Local, this PC only</strong> · <code>POST …/google/connection/attempts/{{googleAttemptId}}/cancel</code> · Bearer (collection auth) · <strong>External</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Cancels this Host's open sign-in attempt (closed on the PC when the cloud cannot be reached). No body. Answer: the attempt, <code>cancelled</code>. The existing connection is unchanged. Skipped while <code>googleAttemptId</code> is empty. LAN: <code>403 GOOGLE_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5v.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","connection","attempts","{{googleAttemptId}}","cancel"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"96584234-8b68-b58a-9805-58b3f9a3916d","name":"200 – attempt cancelled (synthetic)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/google/connection/attempts/{{googleAttemptId}}/cancel","description":"**Local, this PC only** · `POST …/google/connection/attempts/{{googleAttemptId}}/cancel` · Bearer (collection auth) · **External** (guarded by `confirmMutating`)\n\n---\n\n**Mutating — run manually.** Cancels this Host's open sign-in attempt (closed on the PC when the cloud cannot be reached). No body. Answer: the attempt, `cancelled`. The existing connection is unchanged. Skipped while `googleAttemptId` is empty. LAN: `403 GOOGLE_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5v."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"94f28b4c5d6e7f8091a2b3c4d5e6f708","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"attemptId\": \"gst_00000000000000000000000000\", \"status\": \"cancelled\", \"failureCode\": null, \"expiresUtc\": \"2026-10-18T06:20:00Z\", \"connection\": null, \"cloudReachable\": true },\n  \"metadata\": {}\n}"}],"_postman_id":"95605ff8-3121-c4ca-7963-68f3cb4b4253"},{"name":"⚠⚠ Google connection – confirm (use this account)","id":"525a7cb0-133b-6752-1477-d0db8101720d","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"connectionId\": \"{{googleConnectionId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/connection/confirm","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/google/connection/confirm</code> · Bearer (collection auth) · <strong>HIGH IMPACT: makes the signed-in Google account this organization's connection</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Do not run without the owner's approval; normally the window's \"Use this account\".</strong> Body <code>{ \"connectionId\": \"gcn_…\" }</code> (the id the status shows in <code>confirm</code>). On a switch, the previous account is replaced: Sheets exports bound to it wait for it, and Drive backups go to the new account. Answer: the status projection. <strong>Recovery:</strong> sign in again with the previous account and confirm it. Run guard: <code>confirmHighImpact = POST /api/v1/google/connection/confirm</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5v.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","connection","confirm"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"767930e2-0433-4846-2b24-1a039d33de4b","name":"200 – account confirmed (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"connectionId\": \"{{googleConnectionId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/connection/confirm","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/google/connection/confirm` · Bearer (collection auth) · **HIGH IMPACT: makes the signed-in Google account this organization's connection** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Do not run without the owner's approval; normally the window's \"Use this account\".** Body `{ \"connectionId\": \"gcn_…\" }` (the id the status shows in `confirm`). On a switch, the previous account is replaced: Sheets exports bound to it wait for it, and Drive backups go to the new account. Answer: the status projection. **Recovery:** sign in again with the previous account and confirm it. Run guard: `confirmHighImpact = POST /api/v1/google/connection/confirm`.\n\nContract: `docs/LOCAL-API.md` section 5v."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"a5039c5d6e7f8091a2b3c4d5e6f70819"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"state\": \"connected\", \"connectionId\": \"gcn_00000000000000000000000000\", \"account\": { \"email\": \"owner@example.com\", \"name\": \"Example Owner\" }, \"scopes\": [\"drive.file\", \"spreadsheets\", \"openid\", \"email\"] },\n  \"metadata\": {}\n}"}],"_postman_id":"525a7cb0-133b-6752-1477-d0db8101720d"},{"name":"⚠ Google connection – reject (not my account)","id":"2407c19d-2f3c-ccd2-b538-ea80bd2b6b73","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"connectionId\": \"{{googleConnectionId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/connection/reject","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/google/connection/reject</code> · Bearer (collection auth) · <strong>External</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Mutating — run manually; normally the window's \"Not my account\".</strong> Rejects the account waiting for confirmation (<code>confirm</code> state); a confirmed connection is not affected. Body <code>{ \"connectionId\": \"gcn_…\" }</code>. Answer: the status projection. LAN: <code>403 GOOGLE_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5v.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","connection","reject"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"a5ee8cfe-9060-9cb9-b31f-721d8475e21f","name":"200 – waiting account rejected (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"connectionId\": \"{{googleConnectionId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/connection/reject","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/google/connection/reject` · Bearer (collection auth) · **External** (guarded by `confirmMutating`)\n\n---\n\n**Mutating — run manually; normally the window's \"Not my account\".** Rejects the account waiting for confirmation (`confirm` state); a confirmed connection is not affected. Body `{ \"connectionId\": \"gcn_…\" }`. Answer: the status projection. LAN: `403 GOOGLE_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5v."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"b614ad6e7f8091a2b3c4d5e6f708192a","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"state\": \"not_signed_in\", \"connectionId\": null, \"account\": null, \"scopes\": [] },\n  \"metadata\": {}\n}"}],"_postman_id":"2407c19d-2f3c-ccd2-b538-ea80bd2b6b73"},{"name":"⚠⚠ Google connection – disconnect","id":"b5bacaa7-6130-ce37-5589-d18af1ce7ae2","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"connectionId\": \"{{googleConnectionId}}\",\n  \"reason\": \"Disconnected from Postman (test)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/connection/disconnect","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/google/connection/disconnect</code> · Bearer (collection auth) · <strong>HIGH IMPACT: disconnects the organization's Google account</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Do not run without the owner's approval.</strong> Body <code>{ \"connectionId\": \"gcn_…\", \"reason\"?: ≤ 255 characters }</code>. The cloud revokes the connection; this PC drops its leased token at once. Effects: every Sheets export waits (<code>waiting_for_account</code>), Drive backups stop, the backup status shows no Google account. Answer: the status projection. <strong>Recovery:</strong> a new interactive sign-in from the AI Zeny window with the same account (Google consent in the browser), then confirm; exports bound to that account then run one catch-up. Run guard: <code>confirmHighImpact = POST /api/v1/google/connection/disconnect</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5v.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","connection","disconnect"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"33a28c28-8351-db93-4691-7099faaff719","name":"200 – disconnected (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"connectionId\": \"{{googleConnectionId}}\",\n  \"reason\": \"Disconnected from Postman (test)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/connection/disconnect","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/google/connection/disconnect` · Bearer (collection auth) · **HIGH IMPACT: disconnects the organization's Google account** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Do not run without the owner's approval.** Body `{ \"connectionId\": \"gcn_…\", \"reason\"?: ≤ 255 characters }`. The cloud revokes the connection; this PC drops its leased token at once. Effects: every Sheets export waits (`waiting_for_account`), Drive backups stop, the backup status shows no Google account. Answer: the status projection. **Recovery:** a new interactive sign-in from the AI Zeny window with the same account (Google consent in the browser), then confirm; exports bound to that account then run one catch-up. Run guard: `confirmHighImpact = POST /api/v1/google/connection/disconnect`.\n\nContract: `docs/LOCAL-API.md` section 5v."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"c725be7f8091a2b3c4d5e6f708192a3b","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"state\": \"not_signed_in\", \"connectionId\": null, \"account\": null, \"scopes\": [] },\n  \"metadata\": {}\n}"}],"_postman_id":"b5bacaa7-6130-ce37-5589-d18af1ce7ae2"},{"name":"⚠ Google sign-in – return link check","id":"c2fbcfa7-dece-c7ed-41f0-d0e5a1584436","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"attemptId\": \"{{googleAttemptId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/connection/return","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/google/connection/return</code> · Bearer (collection auth) · Internal to the <code>aizeny://</code> return link (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Used by the Launcher</strong> when the browser hands back an <code>aizeny://</code> link (OD-G9, off by default at the cloud). Body <code>{ \"attemptId\": \"gst_…\" }</code>. Answer <code>{ matches }</code>: true only for this Host's open or just-completed attempt; nothing else changes (the window is brought to front by the Launcher, not by this route). Skipped while <code>googleAttemptId</code> is empty. LAN: <code>403 GOOGLE_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5v.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","connection","return"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"d2812e9c-e5e2-5eac-7f46-7dc61bf05982","name":"200 – not this PC's sign-in (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"attemptId\": \"{{googleAttemptId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/connection/return","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/google/connection/return` · Bearer (collection auth) · Internal to the `aizeny://` return link (guarded by `confirmMutating`)\n\n---\n\n**Used by the Launcher** when the browser hands back an `aizeny://` link (OD-G9, off by default at the cloud). Body `{ \"attemptId\": \"gst_…\" }`. Answer `{ matches }`: true only for this Host's open or just-completed attempt; nothing else changes (the window is brought to front by the Launcher, not by this route). Skipped while `googleAttemptId` is empty. LAN: `403 GOOGLE_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5v."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"d836cf8091a2b3c4d5e6f708192a3b4c","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"matches\": false },\n  \"metadata\": {}\n}"}],"_postman_id":"c2fbcfa7-dece-c7ed-41f0-d0e5a1584436"},{"name":"⚠ Sheets export – preview a source","id":"2eb3ff19-03eb-5c2d-615f-a71a13ad2587","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"source\": {\n    \"kind\": \"operation\",\n    \"operation\": \"busy.units.query\",\n    \"companyCode\": \"{{companyCode}}\",\n    \"financialYear\": \"{{financialYear}}\",\n    \"request\": {}\n  },\n  \"maxRows\": 20\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/exports/preview","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/google/exports/preview</code> · Bearer (collection auth) · Source preview, guarded by the existing one-send <code>confirmMutating</code> convention. It reads the configured BUSY source and does not write a Google sheet or save an export.</p>\n<p>The body example is a safe operation source: <code>{source:{kind:'operation',operation:'busy.units.query',companyCode,financialYear,request:{}},maxRows:20}</code>. The source may instead select a saved query. A selected <code>source.script</code> or the company's default transform runs with <code>via:'preview'</code> on each page. The response includes ordered columns/rows, <code>rowCount,columnCount,pageCount,paged,pageSize,rowsPath,transform,perPageTransform,numbersAsText,notes</code>.</p>\n<p>FL-18 preview policy: read-only transforms and message-history <code>get/list/summary</code> are allowed; message mutations and external <code>http.request</code> are refused before effect, including in nested scripts and when <code>allowHttp:true</code>. A transform effect refusal is HTTP 403 with structured <code>metadata.error.code: SCRIPT_PREVIEW_EFFECT_REFUSED</code>; this is a failed preview, not a successful table. Other source failures keep their existing <code>SHEET_EXPORT_SOURCE_FAILED</code> mapping. Other documented source/mapping/provider refusals remain possible. This route does not read Google; any effects of arbitrary BUSY reads/saved queries are outside the script-helper policy.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> §5x.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","exports","preview"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"aa52856b-b5b8-d1f7-af13-6a22e01c846b","name":"200 – units preview (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"source\": {\n    \"kind\": \"operation\",\n    \"operation\": \"busy.units.query\",\n    \"companyCode\": \"{{companyCode}}\",\n    \"financialYear\": \"{{financialYear}}\",\n    \"request\": {}\n  },\n  \"maxRows\": 20\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/exports/preview","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/google/exports/preview` · Bearer (collection auth) · Source preview, guarded by the existing one-send `confirmMutating` convention. It reads the configured BUSY source and does not write a Google sheet or save an export.\n\nThe body example is a safe operation source: `{source:{kind:'operation',operation:'busy.units.query',companyCode,financialYear,request:{}},maxRows:20}`. The source may instead select a saved query. A selected `source.script` or the company's default transform runs with `via:'preview'` on each page. The response includes ordered columns/rows, `rowCount,columnCount,pageCount,paged,pageSize,rowsPath,transform,perPageTransform,numbersAsText,notes`.\n\nFL-18 preview policy: read-only transforms and message-history `get/list/summary` are allowed; message mutations and external `http.request` are refused before effect, including in nested scripts and when `allowHttp:true`. A transform effect refusal is HTTP 403 with structured `metadata.error.code: SCRIPT_PREVIEW_EFFECT_REFUSED`; this is a failed preview, not a successful table. Other source failures keep their existing `SHEET_EXPORT_SOURCE_FAILED` mapping. Other documented source/mapping/provider refusals remain possible. This route does not read Google; any effects of arbitrary BUSY reads/saved queries are outside the script-helper policy.\n\nContract: `docs/LOCAL-API.md` §5x."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"e947d091a2b3c4d5e6f708192a3b4c5d","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"columns\": [\"unit_id\", \"unit_name\", \"unit_print_name\"],\n    \"rows\": [[1180, \"Pcs.\", \"Pcs.\"], [1181, \"Kgs.\", \"Kgs.\"]],\n    \"rowCount\": 2,\n    \"pages\": 1,\n    \"transform\": null,\n    \"perPageTransform\": false,\n    \"numbersAsText\": [],\n    \"notes\": []\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"2eb3ff19-03eb-5c2d-615f-a71a13ad2587"},{"name":"⚠⚠ Sheets export – create (writes a Google sheet on its schedule)","id":"09a7f73f-2e01-adf7-7934-f5ff5b4fcf3e","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"name\": \"{{googleExportName}}\",\n  \"source\": {\n    \"kind\": \"operation\",\n    \"operation\": \"busy.units.query\",\n    \"companyCode\": \"{{companyCode}}\",\n    \"financialYear\": \"{{financialYear}}\",\n    \"request\": {}\n  },\n  \"destination\": {\n    \"spreadsheetId\": \"{{googleSpreadsheetId}}\",\n    \"sheetId\": {{googleSheetId}}\n  },\n  \"intervalMinutes\": 60,\n  \"paused\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/exports","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/google/exports</code> · Bearer (collection auth) · <strong>HIGH IMPACT: an export replaces a Google sheet tab with BUSY data on every run</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Do not run without the owner's approval.</strong> Body <code>{ name, source, rowsPath?, columns?, destination: { spreadsheetId (id or link), sheetId }, intervalMinutes? (10-1440, default 30), paused?, confirmTakeover? }</code>. FULL REFRESH only: the tab's rows from 5 down are replaced on every run (rows 1-4 are the customer's; A1 = \"Last export: …\"); a non-empty tab needs <code>confirmTakeover: true</code>. The sample saves the export <strong>paused</strong>. One export per tab. The Host checks the destination with Google before saving. Answer: the export. Refusals <code>400 SHEET_EXPORT_INVALID</code>, <code>409 SHEET_EXPORT_NAME_TAKEN</code> / <code>SHEET_EXPORT_DESTINATION_TAKEN</code> / takeover needed, Google codes (<code>GOOGLE_SHEETS_NOT_FOUND</code>, <code>…_PERMISSION_DENIED</code>).</p>\n<p><strong>Recovery:</strong> '⚠⚠ Sheets export – delete'; the tab keeps what was written. Run guard: <code>confirmHighImpact = POST /api/v1/google/exports</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5x.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","exports"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"79263d2f-e30c-b2f2-bb83-ca69f257588c","name":"409 – that tab is already written by another export (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"name\": \"{{googleExportName}}\",\n  \"source\": {\n    \"kind\": \"operation\",\n    \"operation\": \"busy.units.query\",\n    \"companyCode\": \"{{companyCode}}\",\n    \"financialYear\": \"{{financialYear}}\",\n    \"request\": {}\n  },\n  \"destination\": {\n    \"spreadsheetId\": \"{{googleSpreadsheetId}}\",\n    \"sheetId\": {{googleSheetId}}\n  },\n  \"intervalMinutes\": 60,\n  \"paused\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/exports","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/google/exports` · Bearer (collection auth) · **HIGH IMPACT: an export replaces a Google sheet tab with BUSY data on every run** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Do not run without the owner's approval.** Body `{ name, source, rowsPath?, columns?, destination: { spreadsheetId (id or link), sheetId }, intervalMinutes? (10-1440, default 30), paused?, confirmTakeover? }`. FULL REFRESH only: the tab's rows from 5 down are replaced on every run (rows 1-4 are the customer's; A1 = \"Last export: …\"); a non-empty tab needs `confirmTakeover: true`. The sample saves the export **paused**. One export per tab. The Host checks the destination with Google before saving. Answer: the export. Refusals `400 SHEET_EXPORT_INVALID`, `409 SHEET_EXPORT_NAME_TAKEN` / `SHEET_EXPORT_DESTINATION_TAKEN` / takeover needed, Google codes (`GOOGLE_SHEETS_NOT_FOUND`, `…_PERMISSION_DENIED`).\n\n**Recovery:** '⚠⚠ Sheets export – delete'; the tab keeps what was written. Run guard: `confirmHighImpact = POST /api/v1/google/exports`.\n\nContract: `docs/LOCAL-API.md` section 5x."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"fa58e1b3c4d5e6f708192a3b4c5d6e7f","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": { \"code\": \"SHEET_EXPORT_DESTINATION_TAKEN\", \"message\": \"Another export on this PC already writes that tab. Choose another tab.\", \"field\": \"destination.sheetId\" },\n    \"requestId\": \"fa58e1b3c4d5e6f708192a3b4c5d6e7f\"\n  }\n}"}],"_postman_id":"09a7f73f-2e01-adf7-7934-f5ff5b4fcf3e"},{"name":"⚠⚠ Sheets export – change","id":"e67a0393-114f-27df-10e9-fc33118af65b","request":{"method":"PUT","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"name\": \"{{googleExportName}}\",\n  \"source\": {\n    \"kind\": \"operation\",\n    \"operation\": \"busy.units.query\",\n    \"companyCode\": \"{{companyCode}}\",\n    \"financialYear\": \"{{financialYear}}\",\n    \"request\": {}\n  },\n  \"destination\": {\n    \"spreadsheetId\": \"{{googleSpreadsheetId}}\",\n    \"sheetId\": {{googleSheetId}}\n  },\n  \"intervalMinutes\": 60,\n  \"paused\": true,\n  \"expectedRevision\": {{googleExportRevision}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}","description":"<p><strong>Local, this PC only</strong> · <code>PUT {{baseUrl}}/api/v1/google/exports/{{googleExportName}}</code> · Bearer (collection auth) · <strong>HIGH IMPACT: changes what is written to a Google sheet</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Do not run without the owner's approval — it changes the owner's live exports.</strong> The create body plus <code>expectedRevision</code> (read it with 'Sheets export – view'); a stale revision is <code>409</code> and nothing is overwritten. Saving with another Google account connected rebinds the export to that account after the destination was checked with it. <strong>Recovery:</strong> send the previous definition back (copy it from 'Sheets export – view' first). Run guard: <code>confirmHighImpact = PUT /api/v1/google/exports/{name}</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5x.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","exports","{{googleExportName}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"fc83e7a3-6da7-dea7-8299-2528d42b1c51","name":"200 – export changed (synthetic)","originalRequest":{"method":"PUT","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"name\": \"{{googleExportName}}\",\n  \"source\": {\n    \"kind\": \"operation\",\n    \"operation\": \"busy.units.query\",\n    \"companyCode\": \"{{companyCode}}\",\n    \"financialYear\": \"{{financialYear}}\",\n    \"request\": {}\n  },\n  \"destination\": {\n    \"spreadsheetId\": \"{{googleSpreadsheetId}}\",\n    \"sheetId\": {{googleSheetId}}\n  },\n  \"intervalMinutes\": 60,\n  \"paused\": true,\n  \"expectedRevision\": {{googleExportRevision}}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}","description":"**Local, this PC only** · `PUT {{baseUrl}}/api/v1/google/exports/{{googleExportName}}` · Bearer (collection auth) · **HIGH IMPACT: changes what is written to a Google sheet** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Do not run without the owner's approval — it changes the owner's live exports.** The create body plus `expectedRevision` (read it with 'Sheets export – view'); a stale revision is `409` and nothing is overwritten. Saving with another Google account connected rebinds the export to that account after the destination was checked with it. **Recovery:** send the previous definition back (copy it from 'Sheets export – view' first). Run guard: `confirmHighImpact = PUT /api/v1/google/exports/{name}`.\n\nContract: `docs/LOCAL-API.md` section 5x."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"0b69f2c4d5e6f708192a3b4c5d6e7f80","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"name\": \"Units to Sheet\",\n    \"source\": { \"kind\": \"operation\", \"operation\": \"busy.units.query\", \"queryName\": null, \"companyCode\": \"COMP0002\", \"financialYear\": \"2026\", \"request\": {}, \"parameters\": null, \"script\": null },\n    \"destination\": { \"spreadsheetId\": \"1AbCdEfGhIjKlMnOpQrStUvWxYz0123456789\", \"spreadsheetTitle\": \"Example export\", \"sheetId\": 0, \"sheetTitle\": \"Units\", \"googleAccount\": \"owner@example.com\", \"takeoverConfirmedUtc\": null, \"takeoverFromJob\": null },\n    \"intervalMinutes\": 60,\n    \"paused\": true,\n    \"revision\": 3,\n    \"status\": { \"state\": \"paused\", \"attention\": null, \"connectedAccount\": true, \"active\": null, \"latest\": null, \"lastSucceeded\": \"2026-10-18T05:30:05Z\", \"nextRunUtc\": null, \"retryUtc\": null },\n    \"notes\": []\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"e67a0393-114f-27df-10e9-fc33118af65b"},{"name":"⚠⚠ Sheets export – delete","id":"46ada50b-03b6-c84a-877e-0fd7f2932deb","request":{"method":"DELETE","header":[],"url":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}?revision={{googleExportRevision}}","description":"<p><strong>Local, this PC only</strong> · <code>DELETE {{baseUrl}}/api/v1/google/exports/{{googleExportName}}?revision=…</code> · Bearer (collection auth) · <strong>HIGH IMPACT / destructive: removes one of the owner's exports</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Do not run without the owner's approval.</strong> Deletes the export definition permanently; the Google tab keeps what was written; run history stays in <code>runtime.db</code>. Answer <code>{ deleted }</code>; <code>409</code> for a stale revision or an active run. <strong>Recovery:</strong> create it again from a copy of 'Sheets export – view' (the next run replaces the tab again). Run guard: <code>confirmHighImpact = DELETE /api/v1/google/exports/{name}</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5x.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","exports","{{googleExportName}}"],"host":["{{baseUrl}}"],"query":[{"description":{"content":"<p>the revision you read (required)</p>\n","type":"text/plain"},"key":"revision","value":"{{googleExportRevision}}"}],"variable":[]}},"response":[{"id":"ded0045c-d4dd-23cf-7c33-8080f8a555bb","name":"200 – export deleted (synthetic)","originalRequest":{"method":"DELETE","header":[],"url":{"raw":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}?revision={{googleExportRevision}}","host":["{{baseUrl}}"],"path":["api","v1","google","exports","{{googleExportName}}"],"query":[{"description":"the revision you read (required)","value":"{{googleExportRevision}}","key":"revision"}]},"description":"**Local, this PC only** · `DELETE {{baseUrl}}/api/v1/google/exports/{{googleExportName}}?revision=…` · Bearer (collection auth) · **HIGH IMPACT / destructive: removes one of the owner's exports** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Do not run without the owner's approval.** Deletes the export definition permanently; the Google tab keeps what was written; run history stays in `runtime.db`. Answer `{ deleted }`; `409` for a stale revision or an active run. **Recovery:** create it again from a copy of 'Sheets export – view' (the next run replaces the tab again). Run guard: `confirmHighImpact = DELETE /api/v1/google/exports/{name}`.\n\nContract: `docs/LOCAL-API.md` section 5x."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"1c7a03d5e6f708192a3b4c5d6e7f8091","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"deleted\": true },\n  \"metadata\": {}\n}"}],"_postman_id":"46ada50b-03b6-c84a-877e-0fd7f2932deb"},{"name":"⚠⚠ Sheets export – run now (writes the Google sheet)","id":"a9677344-a846-8c31-d916-55949c38489b","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}/run","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/google/exports/{{googleExportName}}/run</code> · Bearer (collection auth) · <strong>HIGH IMPACT: replaces the destination tab with BUSY data now</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Do not run without the owner's approval.</strong> Starts one manual run (own history; never shifts the automatic timing; works while paused). Answer: the run. Refusals <code>409 SHEET_EXPORT_RUN_ACTIVE</code>, <code>SHEET_EXPORT_DESTINATION_BUSY</code>, <code>SHEET_EXPORT_ACCOUNT_MISMATCH</code> (another Google account connected); an earlier <code>uncertain</code> run blocks a new write until it is checked. A run is bounded to 15 minutes; a lost commit answer is reconciled from the sheet's marker, never resent blindly. <strong>Recovery:</strong> the previous tab contents are gone after a successful run (Google Sheets version history keeps them); stop with '⚠ Sheets export – stop the run'. Run guard: <code>confirmHighImpact = POST /api/v1/google/exports/{name}/run</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5x.</p>\n<p>Unresolved uncertain run: before a new run is claimed, AI Zeny checks prior runs of this export and any export that targeted the same destination tab. Only the prior commit marker or surviving staging tab can settle an outcome. If it remains uncertain or Google cannot be read, HTTP 409 SHEET_EXPORT_UNCERTAIN_BLOCKED names the prior numeric run ID; no new run is claimed and no Sheets write occurs. The block survives a Host restart. Inspect export history and destination evidence; never blindly retry, clear history, or treat time elapsed as resolution. A definitive manual resolution procedure for missing evidence awaits an owner decision. HTTP 200 acknowledges only a started run, not final completion.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","exports","{{googleExportName}}","run"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"6e4244ce-59d7-0bc0-c3c4-e6fe9e26f453","name":"409 – a run is already active (synthetic)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}/run","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/google/exports/{{googleExportName}}/run` · Bearer (collection auth) · **HIGH IMPACT: replaces the destination tab with BUSY data now** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Do not run without the owner's approval.** Starts one manual run (own history; never shifts the automatic timing; works while paused). Answer: the run. Refusals `409 SHEET_EXPORT_RUN_ACTIVE`, `SHEET_EXPORT_DESTINATION_BUSY`, `SHEET_EXPORT_ACCOUNT_MISMATCH` (another Google account connected); an earlier `uncertain` run blocks a new write until it is checked. A run is bounded to 15 minutes; a lost commit answer is reconciled from the sheet's marker, never resent blindly. **Recovery:** the previous tab contents are gone after a successful run (Google Sheets version history keeps them); stop with '⚠ Sheets export – stop the run'. Run guard: `confirmHighImpact = POST /api/v1/google/exports/{name}/run`.\n\nContract: `docs/LOCAL-API.md` section 5x.\n\nUnresolved uncertain run: before a new run is claimed, AI Zeny checks prior runs of this export and any export that targeted the same destination tab. Only the prior commit marker or surviving staging tab can settle an outcome. If it remains uncertain or Google cannot be read, HTTP 409 SHEET_EXPORT_UNCERTAIN_BLOCKED names the prior numeric run ID; no new run is claimed and no Sheets write occurs. The block survives a Host restart. Inspect export history and destination evidence; never blindly retry, clear history, or treat time elapsed as resolution. A definitive manual resolution procedure for missing evidence awaits an owner decision. HTTP 200 acknowledges only a started run, not final completion.\n"},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"2d8b14e6f708192a3b4c5d6e7f8091a2"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": { \"code\": \"SHEET_EXPORT_RUN_ACTIVE\", \"message\": \"This export is already running.\" },\n    \"requestId\": \"2d8b14e6f708192a3b4c5d6e7f8091a2\"\n  }\n}"},{"id":"76b9b523-6897-6865-0b99-941e9bb23ad1","name":"409 unresolved prior run (synthetic)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}/run","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/google/exports/{{googleExportName}}/run` · Bearer (collection auth) · **HIGH IMPACT: replaces the destination tab with BUSY data now** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Do not run without the owner's approval.** Starts one manual run (own history; never shifts the automatic timing; works while paused). Answer: the run. Refusals `409 SHEET_EXPORT_RUN_ACTIVE`, `SHEET_EXPORT_DESTINATION_BUSY`, `SHEET_EXPORT_ACCOUNT_MISMATCH` (another Google account connected); an earlier `uncertain` run blocks a new write until it is checked. A run is bounded to 15 minutes; a lost commit answer is reconciled from the sheet's marker, never resent blindly. **Recovery:** the previous tab contents are gone after a successful run (Google Sheets version history keeps them); stop with '⚠ Sheets export – stop the run'. Run guard: `confirmHighImpact = POST /api/v1/google/exports/{name}/run`.\n\nContract: `docs/LOCAL-API.md` section 5x.\n\nUnresolved uncertain run: before a new run is claimed, AI Zeny checks prior runs of this export and any export that targeted the same destination tab. Only the prior commit marker or surviving staging tab can settle an outcome. If it remains uncertain or Google cannot be read, HTTP 409 SHEET_EXPORT_UNCERTAIN_BLOCKED names the prior numeric run ID; no new run is claimed and no Sheets write occurs. The block survives a Host restart. Inspect export history and destination evidence; never blindly retry, clear history, or treat time elapsed as resolution. A definitive manual resolution procedure for missing evidence awaits an owner decision. HTTP 200 acknowledges only a started run, not final completion.\n"},"status":"Conflict","code":409,"_postman_previewlanguage":"Text","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SHEET_EXPORT_UNCERTAIN_BLOCKED\",\n      \"message\": \"Prior Sheets export run 17 still has an uncertain outcome for this export or destination. No new run was started; inspect its history and destination evidence.\",\n      \"details\": {\n        \"priorRunId\": 17\n      }\n    },\n    \"requestId\": \"synthetic-fl57-001\"\n  }\n}"}],"_postman_id":"a9677344-a846-8c31-d916-55949c38489b"},{"name":"⚠ Sheets export – stop the run","id":"ae0e1b2f-6a92-b8b8-4bd9-ba24f8570574","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}/cancel","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/google/exports/{{googleExportName}}/cancel</code> · Bearer (collection auth) · <strong>Changes AI Zeny on the PC</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Stops the export's active run (recorded <code>cancelled</code>; at the final commit step it may be <code>uncertain</code>, then checked from the sheet's marker). The schedule is not paused. Answer: the export. <code>409</code> when no run is active. Skipped while <code>googleExportName</code> is empty.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5x.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","exports","{{googleExportName}}","cancel"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"432076c1-9b23-f706-cbba-027d03a81a05","name":"200 – run stopped (synthetic)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}/cancel","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/google/exports/{{googleExportName}}/cancel` · Bearer (collection auth) · **Changes AI Zeny on the PC** (guarded by `confirmMutating`)\n\n---\n\n**Mutating — run manually.** Stops the export's active run (recorded `cancelled`; at the final commit step it may be `uncertain`, then checked from the sheet's marker). The schedule is not paused. Answer: the export. `409` when no run is active. Skipped while `googleExportName` is empty.\n\nContract: `docs/LOCAL-API.md` section 5x."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"3e9c25f708192a3b4c5d6e7f8091a2b3","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"name\": \"Units to Sheet\", \"paused\": false, \"status\": { \"state\": \"scheduled\", \"attention\": null, \"connectedAccount\": true, \"active\": null, \"latest\": { \"status\": \"cancelled\", \"finishedUtc\": \"2026-10-18T06:05:02Z\" }, \"lastSucceeded\": \"2026-10-18T05:30:05Z\", \"nextRunUtc\": \"2026-10-18T06:30:00Z\", \"retryUtc\": null } },\n  \"metadata\": {}\n}"}],"_postman_id":"ae0e1b2f-6a92-b8b8-4bd9-ba24f8570574"},{"name":"⚠ Sheets export – pause","id":"ed96f4b8-4980-59d9-6091-f8664cabe809","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}/pause","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/google/exports/{{googleExportName}}/pause</code> · Bearer (collection auth) · <strong>Changes AI Zeny on the PC</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Stops automatic runs of one export (Run now still works). Answer: the export (<code>paused: true</code>). <strong>Undo:</strong> '⚠⚠ Sheets export – resume'. Skipped while <code>googleExportName</code> is empty.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5x.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","exports","{{googleExportName}}","pause"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"9a674064-fd7d-1a98-629a-1dd5631b08ad","name":"200 – export paused (synthetic)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}/pause","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/google/exports/{{googleExportName}}/pause` · Bearer (collection auth) · **Changes AI Zeny on the PC** (guarded by `confirmMutating`)\n\n---\n\n**Mutating — run manually.** Stops automatic runs of one export (Run now still works). Answer: the export (`paused: true`). **Undo:** '⚠⚠ Sheets export – resume'. Skipped while `googleExportName` is empty.\n\nContract: `docs/LOCAL-API.md` section 5x."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"4fad36f708192a3b4c5d6e7f8091a2c4"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"name\": \"Units to Sheet\", \"paused\": true, \"status\": { \"state\": \"paused\", \"attention\": null, \"connectedAccount\": true, \"active\": null, \"latest\": null, \"lastSucceeded\": \"2026-10-18T05:30:05Z\", \"nextRunUtc\": null, \"retryUtc\": null } },\n  \"metadata\": {}\n}"}],"_postman_id":"ed96f4b8-4980-59d9-6091-f8664cabe809"},{"name":"⚠⚠ Sheets export – resume (automatic writes start again)","id":"96765ae6-e03d-77fb-2a18-84e68793d9d3","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}/resume","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/google/exports/{{googleExportName}}/resume</code> · Bearer (collection auth) · <strong>HIGH IMPACT: automatic writes to the Google tab start again</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Do not run without the owner's approval.</strong> Plans the next automatic run one interval later (missed intervals are never replayed). Answer: the export (<code>paused: false</code>). <strong>Undo:</strong> '⚠ Sheets export – pause'. Run guard: <code>confirmHighImpact = POST /api/v1/google/exports/{name}/resume</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5x.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","exports","{{googleExportName}}","resume"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"b9fcd1c6-f7c3-80ae-d016-b09fe94d7a10","name":"200 – export resumed (synthetic)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/google/exports/{{googleExportName}}/resume","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/google/exports/{{googleExportName}}/resume` · Bearer (collection auth) · **HIGH IMPACT: automatic writes to the Google tab start again** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Do not run without the owner's approval.** Plans the next automatic run one interval later (missed intervals are never replayed). Answer: the export (`paused: false`). **Undo:** '⚠ Sheets export – pause'. Run guard: `confirmHighImpact = POST /api/v1/google/exports/{name}/resume`.\n\nContract: `docs/LOCAL-API.md` section 5x."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"50be4708192a3b4c5d6e7f8091a2b3d5","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"name\": \"Units to Sheet\", \"paused\": false, \"status\": { \"state\": \"scheduled\", \"attention\": null, \"connectedAccount\": true, \"active\": null, \"latest\": null, \"lastSucceeded\": \"2026-10-18T05:30:05Z\", \"nextRunUtc\": \"2026-10-18T07:05:00Z\", \"retryUtc\": null } },\n  \"metadata\": {}\n}"}],"_postman_id":"96765ae6-e03d-77fb-2a18-84e68793d9d3"},{"name":"⚠ Google spreadsheets – list (calls Google Drive)","id":"7fb3cc4a-fa3a-619c-895f-b0f6539646a2","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/google/spreadsheets","description":"<p><strong>Local, this PC only</strong> · <code>GET {{baseUrl}}/api/v1/google/spreadsheets</code> · Bearer (collection auth) · <strong>External read: calls Google Drive with the leased token</strong> (guarded by <code>confirmMutating</code>, because it reaches an external system)</p>\n<hr />\n<p>The spreadsheets the connected account lets AI Zeny see (<code>drive.file</code>: the ones AI Zeny created or the user picked). Nothing changes. Google failures carry fixed codes (<code>GOOGLE_RATE_LIMITED</code>, <code>GOOGLE_SHEETS_UNAVAILABLE</code>, <code>GOOGLE_SHEETS_PERMISSION_DENIED</code>, …); without a connection <code>409</code>. LAN: <code>403 GOOGLE_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5x.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","spreadsheets"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"a22a8ab4-2ed0-9e55-5076-720848210f24","name":"200 – spreadsheets AI Zeny can see (synthetic)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/google/spreadsheets","description":"**Local, this PC only** · `GET {{baseUrl}}/api/v1/google/spreadsheets` · Bearer (collection auth) · **External read: calls Google Drive with the leased token** (guarded by `confirmMutating`, because it reaches an external system)\n\n---\n\nThe spreadsheets the connected account lets AI Zeny see (`drive.file`: the ones AI Zeny created or the user picked). Nothing changes. Google failures carry fixed codes (`GOOGLE_RATE_LIMITED`, `GOOGLE_SHEETS_UNAVAILABLE`, `GOOGLE_SHEETS_PERMISSION_DENIED`, …); without a connection `409`. LAN: `403 GOOGLE_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5x."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"61cf58192a3b4c5d6e7f8091a2b3c4e6","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    { \"spreadsheetId\": \"1AbCdEfGhIjKlMnOpQrStUvWxYz0123456789\", \"title\": \"Example export\", \"modifiedUtc\": \"2026-10-18T05:30:05Z\" }\n  ],\n  \"metadata\": {}\n}"}],"_postman_id":"7fb3cc4a-fa3a-619c-895f-b0f6539646a2"},{"name":"⚠⚠ Google spreadsheet – create","id":"ba527c74-fd66-8d43-536b-548d1aa0731b","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"title\": \"AI Zeny test export\",\n  \"tabTitle\": \"Units\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/spreadsheets","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/google/spreadsheets</code> · Bearer (collection auth) · <strong>HIGH IMPACT: creates a file in the owner's Google Drive</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Do not run without the owner's approval.</strong> Body <code>{ title, tabTitle? }</code>. Answer: the new spreadsheet with its tabs (sets <code>googleSpreadsheetId</code> and <code>googleSheetId</code>). <strong>Recovery:</strong> delete the file in Google Drive by hand (AI Zeny never deletes Drive files). Run guard: <code>confirmHighImpact = POST /api/v1/google/spreadsheets</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5x.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","spreadsheets"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"c38af589-cae6-bec8-e127-704a702c3b1e","name":"200 – spreadsheet created (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"title\": \"AI Zeny test export\",\n  \"tabTitle\": \"Units\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/spreadsheets","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/google/spreadsheets` · Bearer (collection auth) · **HIGH IMPACT: creates a file in the owner's Google Drive** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Do not run without the owner's approval.** Body `{ title, tabTitle? }`. Answer: the new spreadsheet with its tabs (sets `googleSpreadsheetId` and `googleSheetId`). **Recovery:** delete the file in Google Drive by hand (AI Zeny never deletes Drive files). Run guard: `confirmHighImpact = POST /api/v1/google/spreadsheets`.\n\nContract: `docs/LOCAL-API.md` section 5x."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"72d0692a3b4c5d6e7f8091a2b3c4d5f7"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"spreadsheetId\": \"1ZyXwVuTsRqPoNmLkJiHgFeDcBa9876543210\",\n    \"title\": \"AI Zeny test export\",\n    \"tabs\": [ { \"sheetId\": 0, \"title\": \"Units\", \"rows\": 0, \"writtenBy\": null } ]\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"ba527c74-fd66-8d43-536b-548d1aa0731b"},{"name":"⚠ Google spreadsheet – view its tabs (calls Google)","id":"d1c3a4dd-6a3b-b7a4-f105-fea527e0c750","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/google/spreadsheets/{{googleSpreadsheetId}}","description":"<p><strong>Local, this PC only</strong> · <code>GET {{baseUrl}}/api/v1/google/spreadsheets/{{googleSpreadsheetId}}</code> · Bearer (collection auth) · <strong>External read</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p>The spreadsheet's tabs (staging tabs hidden) with the export on this PC that writes each. Nothing changes. Skipped while <code>googleSpreadsheetId</code> is empty. LAN: <code>403 GOOGLE_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5x.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","spreadsheets","{{googleSpreadsheetId}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"9d77bba9-385e-fa06-c8f2-cfeba51db541","name":"200 – tabs and their writers (synthetic)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/google/spreadsheets/{{googleSpreadsheetId}}","description":"**Local, this PC only** · `GET {{baseUrl}}/api/v1/google/spreadsheets/{{googleSpreadsheetId}}` · Bearer (collection auth) · **External read** (guarded by `confirmMutating`)\n\n---\n\nThe spreadsheet's tabs (staging tabs hidden) with the export on this PC that writes each. Nothing changes. Skipped while `googleSpreadsheetId` is empty. LAN: `403 GOOGLE_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5x."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"83e17a3b4c5d6e7f8091a2b3c4d5e608","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"spreadsheetId\": \"1AbCdEfGhIjKlMnOpQrStUvWxYz0123456789\",\n    \"title\": \"Example export\",\n    \"tabs\": [\n      { \"sheetId\": 0, \"title\": \"Units\", \"rows\": 13, \"writtenBy\": \"Units to Sheet\" },\n      { \"sheetId\": 1857, \"title\": \"Notes\", \"rows\": 4, \"writtenBy\": null }\n    ]\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"d1c3a4dd-6a3b-b7a4-f105-fea527e0c750"},{"name":"⚠⚠ Google spreadsheet – add a tab","id":"75fe4b0c-d592-0b68-5ed8-75bfc94d1590","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"title\": \"Customers\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/spreadsheets/{{googleSpreadsheetId}}/tabs","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/google/spreadsheets/{{googleSpreadsheetId}}/tabs</code> · Bearer (collection auth) · <strong>HIGH IMPACT: changes a Google spreadsheet</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Do not run without the owner's approval.</strong> Body <code>{ title }</code>. Answer: the spreadsheet with the new tab. <strong>Recovery:</strong> remove the tab in Google Sheets by hand. Run guard: <code>confirmHighImpact = POST /api/v1/google/spreadsheets/{id}/tabs</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5x.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","spreadsheets","{{googleSpreadsheetId}}","tabs"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"b4510530-2c24-0f4e-9db3-8db1ae398ac4","name":"200 – tab added (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"title\": \"Customers\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/google/spreadsheets/{{googleSpreadsheetId}}/tabs","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/google/spreadsheets/{{googleSpreadsheetId}}/tabs` · Bearer (collection auth) · **HIGH IMPACT: changes a Google spreadsheet** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Do not run without the owner's approval.** Body `{ title }`. Answer: the spreadsheet with the new tab. **Recovery:** remove the tab in Google Sheets by hand. Run guard: `confirmHighImpact = POST /api/v1/google/spreadsheets/{id}/tabs`.\n\nContract: `docs/LOCAL-API.md` section 5x."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"94f28b4c5d6e7f8091a2b3c4d5e6f719"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"spreadsheetId\": \"1AbCdEfGhIjKlMnOpQrStUvWxYz0123456789\",\n    \"title\": \"Example export\",\n    \"tabs\": [\n      { \"sheetId\": 0, \"title\": \"Units\", \"rows\": 13, \"writtenBy\": \"Units to Sheet\" },\n      { \"sheetId\": 2468, \"title\": \"Customers\", \"rows\": 0, \"writtenBy\": null }\n    ]\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"75fe4b0c-d592-0b68-5ed8-75bfc94d1590"},{"name":"⚠ Google spreadsheet tab – what choosing it replaces (calls Google)","id":"4760f42f-857e-4846-2344-ba04fd22c520","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/google/spreadsheets/{{googleSpreadsheetId}}/tabs/{{googleSheetId}}","description":"<p><strong>Local, this PC only</strong> · <code>GET …/google/spreadsheets/{{googleSpreadsheetId}}/tabs/{{googleSheetId}}</code> · Bearer (collection auth) · <strong>External read</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p>What an export choosing this tab would replace (rows, the current writer) and <code>needsConfirmation</code> (a non-empty tab needs <code>confirmTakeover</code>). Nothing changes. Skipped while the spreadsheet or tab id is empty. LAN: <code>403 GOOGLE_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5x.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","google","spreadsheets","{{googleSpreadsheetId}}","tabs","{{googleSheetId}}"],"host":["{{baseUrl}}"],"query":[{"disabled":true,"description":{"content":"<p>optional: the export that would write it (its own tab needs no takeover)</p>\n","type":"text/plain"},"key":"export","value":"{{googleExportName}}"}],"variable":[]}},"response":[{"id":"58a0bb1f-a774-5677-4495-77caae039f5d","name":"200 – a non-empty tab needs confirmTakeover (synthetic)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{baseUrl}}/api/v1/google/spreadsheets/{{googleSpreadsheetId}}/tabs/{{googleSheetId}}","host":["{{baseUrl}}"],"path":["api","v1","google","spreadsheets","{{googleSpreadsheetId}}","tabs","{{googleSheetId}}"],"query":[{"description":"optional: the export that would write it (its own tab needs no takeover)","key":"export","value":"{{googleExportName}}","disabled":true}]},"description":"**Local, this PC only** · `GET …/google/spreadsheets/{{googleSpreadsheetId}}/tabs/{{googleSheetId}}` · Bearer (collection auth) · **External read** (guarded by `confirmMutating`)\n\n---\n\nWhat an export choosing this tab would replace (rows, the current writer) and `needsConfirmation` (a non-empty tab needs `confirmTakeover`). Nothing changes. Skipped while the spreadsheet or tab id is empty. LAN: `403 GOOGLE_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5x."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"a5039c5d6e7f8091a2b3c4d5e6f7082a","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"spreadsheetId\": \"1AbCdEfGhIjKlMnOpQrStUvWxYz0123456789\", \"sheetId\": 1857, \"title\": \"Notes\", \"rows\": 4, \"writtenBy\": null, \"needsConfirmation\": true },\n  \"metadata\": {}\n}"}],"_postman_id":"4760f42f-857e-4846-2344-ba04fd22c520"}],"id":"254017be-e5e3-b6c7-a46b-bb6a2238b975","_postman_id":"254017be-e5e3-b6c7-a46b-bb6a2238b975","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ Backup & Restore — Google Drive and this PC's settings (this PC only)","item":[{"name":"⚠⚠ Backup – change settings (daily Drive upload on/off, time)","id":"c5e30c82-ecc0-b928-92d8-651c6d4bdbf8","request":{"method":"PUT","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"enabled\": true,\n  \"dailyAt\": \"02:00\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/backup/settings","description":"<p><strong>Local, this PC only</strong> · <code>PUT {{baseUrl}}/api/v1/backup/settings</code> · Bearer (collection auth) · <strong>HIGH IMPACT: turning the daily backup on uploads an encrypted archive to Google Drive every day</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Do not run without the owner's approval.</strong> Body <code>{ enabled, dailyAt: \"HH:mm\" }</code> (the PC's local time; default 02:00). With <code>enabled: true</code> the Host uploads one encrypted backup to Google Drive every day (one catch-up after the PC was off, never a backlog). Answer: the backup status. <strong>Recovery:</strong> send the previous values (read 'Backup – status' first). LAN: <code>403 BACKUP_LOOPBACK_ONLY</code>. Run guard: <code>confirmHighImpact = PUT /api/v1/backup/settings</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5w.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","backup","settings"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"c4fe3c82-e678-ade6-7952-3b85d93ecdd8","name":"200 – daily backup at 02:00 (synthetic)","originalRequest":{"method":"PUT","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"enabled\": true,\n  \"dailyAt\": \"02:00\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/backup/settings","description":"**Local, this PC only** · `PUT {{baseUrl}}/api/v1/backup/settings` · Bearer (collection auth) · **HIGH IMPACT: turning the daily backup on uploads an encrypted archive to Google Drive every day** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Do not run without the owner's approval.** Body `{ enabled, dailyAt: \"HH:mm\" }` (the PC's local time; default 02:00). With `enabled: true` the Host uploads one encrypted backup to Google Drive every day (one catch-up after the PC was off, never a backlog). Answer: the backup status. **Recovery:** send the previous values (read 'Backup – status' first). LAN: `403 BACKUP_LOOPBACK_ONLY`. Run guard: `confirmHighImpact = PUT /api/v1/backup/settings`.\n\nContract: `docs/LOCAL-API.md` section 5w."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"b614ad6e7f8091a2b3c4d5e6f708193b","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"settings\": { \"enabled\": true, \"dailyAt\": \"02:00\", \"timeZone\": \"Asia/Kolkata\", \"folder\": \"AI Zeny Backups\" },\n    \"recoveryKey\": { \"status\": \"saved\", \"keyId\": \"rk_00000000\" },\n    \"nextRun\": { \"kind\": \"daily\", \"utc\": \"2026-10-19T02:00:00Z\" }\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"c5e30c82-ecc0-b928-92d8-651c6d4bdbf8"},{"name":"⚠⚠ Backup – back up now (uploads to Google Drive)","id":"237d867b-b91e-9de6-07d9-def4e4c66e08","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/backup/run","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/backup/run</code> · Bearer (collection auth) · <strong>HIGH IMPACT: uploads an encrypted archive of AI Zeny's settings and message history to the owner's Google Drive</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Do not run without the owner's approval.</strong> No body. Takes <code>settings.db</code> and <code>messaging.db</code> by SQLite online backup (machine-bound values removed; SQL passwords and schedule parameters carried inside the AES-256-GCM encryption), uploads it to the visible Drive folder \"AI Zeny Backups\", verifies the stored object and registers its metadata with the cloud. Never included: the master key, enrollment, the Local API token, runtime history, logs, the Google connection or BUSY's own databases. Back up now never counts as the daily backup. Answer <code>{ runId }</code>; <code>409 BACKUP_RUNNING</code>; without a recovery key or Google connection a refusal. <strong>Recovery:</strong> delete the file in Drive by hand (AI Zeny never deletes backups). Run guard: <code>confirmHighImpact = POST /api/v1/backup/run</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5w.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","backup","run"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"82d81744-09d2-6a0b-62de-2868dff8f8ac","name":"409 – a backup is already running (synthetic)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/backup/run","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/backup/run` · Bearer (collection auth) · **HIGH IMPACT: uploads an encrypted archive of AI Zeny's settings and message history to the owner's Google Drive** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Do not run without the owner's approval.** No body. Takes `settings.db` and `messaging.db` by SQLite online backup (machine-bound values removed; SQL passwords and schedule parameters carried inside the AES-256-GCM encryption), uploads it to the visible Drive folder \"AI Zeny Backups\", verifies the stored object and registers its metadata with the cloud. Never included: the master key, enrollment, the Local API token, runtime history, logs, the Google connection or BUSY's own databases. Back up now never counts as the daily backup. Answer `{ runId }`; `409 BACKUP_RUNNING`; without a recovery key or Google connection a refusal. **Recovery:** delete the file in Drive by hand (AI Zeny never deletes backups). Run guard: `confirmHighImpact = POST /api/v1/backup/run`.\n\nContract: `docs/LOCAL-API.md` section 5w."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"c725be7f8091a2b3c4d5e6f708192a4c","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": { \"code\": \"BACKUP_RUNNING\", \"message\": \"A backup is already running.\" },\n    \"requestId\": \"c725be7f8091a2b3c4d5e6f708192a4c\"\n  }\n}"}],"_postman_id":"237d867b-b91e-9de6-07d9-def4e4c66e08"},{"name":"⚠ Backup – stop the running backup","id":"ec574a11-5121-ec12-dc3c-052eec43d9c5","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/backup/cancel","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/backup/cancel</code> · Bearer (collection auth) · <strong>Changes AI Zeny on the PC</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Stops the backup that is running (a partly uploaded resumable session is abandoned; nothing is registered). No body. Answer: the backup status; <code>409 BACKUP_NOT_RUNNING</code> when none runs (the normal answer when tried on purpose). LAN: <code>403 BACKUP_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5w.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","backup","cancel"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"a27662da-0d2f-2bf0-2775-02feaa1f959b","name":"409 – no backup is running (synthetic)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/backup/cancel","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/backup/cancel` · Bearer (collection auth) · **Changes AI Zeny on the PC** (guarded by `confirmMutating`)\n\n---\n\n**Mutating — run manually.** Stops the backup that is running (a partly uploaded resumable session is abandoned; nothing is registered). No body. Answer: the backup status; `409 BACKUP_NOT_RUNNING` when none runs (the normal answer when tried on purpose). LAN: `403 BACKUP_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5w."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"d836cf8091a2b3c4d5e6f708192a3b5d","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": { \"code\": \"BACKUP_NOT_RUNNING\", \"message\": \"No backup is running.\" },\n    \"requestId\": \"d836cf8091a2b3c4d5e6f708192a3b5d\"\n  }\n}"}],"_postman_id":"ec574a11-5121-ec12-dc3c-052eec43d9c5"},{"name":"⚠⚠ Backup – reveal the recovery key (secret)","id":"88873594-0cf8-ce4e-68e8-4aeffc905afb","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/backup/recovery-key","description":"<p><strong>Local, this PC only</strong> · <code>GET {{baseUrl}}/api/v1/backup/recovery-key</code> · Bearer (collection auth) · <strong>HIGH IMPACT: answers the backup recovery key in clear</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Do not run without the owner's approval, and never in a shared workspace or a CI/Collection Runner log.</strong> Answer <code>{ keyId, recoveryKey }</code> (<code>AZRK-</code> + 14 groups; <code>Cache-Control: no-store</code>). Anyone with the key and a backup archive can read the backed-up settings (including SQL passwords). Prefer the AI Zeny window (Settings → Backup &amp; restore, shown only while unlocked). The test below never prints the key. Run guard: <code>confirmHighImpact = GET /api/v1/backup/recovery-key</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5w.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","backup","recovery-key"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"9e39889d-b9e6-4dd3-8129-772ee0fa1e80","name":"200 – the key (synthetic placeholder, never a real key)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/backup/recovery-key","description":"**Local, this PC only** · `GET {{baseUrl}}/api/v1/backup/recovery-key` · Bearer (collection auth) · **HIGH IMPACT: answers the backup recovery key in clear** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Do not run without the owner's approval, and never in a shared workspace or a CI/Collection Runner log.** Answer `{ keyId, recoveryKey }` (`AZRK-` + 14 groups; `Cache-Control: no-store`). Anyone with the key and a backup archive can read the backed-up settings (including SQL passwords). Prefer the AI Zeny window (Settings → Backup & restore, shown only while unlocked). The test below never prints the key. Run guard: `confirmHighImpact = GET /api/v1/backup/recovery-key`.\n\nContract: `docs/LOCAL-API.md` section 5w."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"e947d091a2b3c4d5e6f708192a3b4c6e","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"keyId\": \"rk_00000000\", \"recoveryKey\": \"AZRK-EXAMPLE-NOT-A-REAL-KEY\" },\n  \"metadata\": {}\n}"}],"_postman_id":"88873594-0cf8-ce4e-68e8-4aeffc905afb"},{"name":"⚠ Backup – confirm the recovery key was saved","id":"41694792-78b4-bddc-1326-f9af9320d0b1","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/backup/recovery-key/confirm-saved","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/backup/recovery-key/confirm-saved</code> · Bearer (collection auth) · <strong>Changes AI Zeny on the PC</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Mutating — the owner's own statement.</strong> Records that the owner saved the recovery key (the window's <strong>I saved the key</strong>); it removes the \"save your key\" reminder. Only the owner should send it, after actually saving the key offline. No body. Answer: the backup status. LAN: <code>403 BACKUP_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5w.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","backup","recovery-key","confirm-saved"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"db962336-662d-f022-94df-e86aa310194d","name":"200 – key marked as saved (synthetic)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/backup/recovery-key/confirm-saved","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/backup/recovery-key/confirm-saved` · Bearer (collection auth) · **Changes AI Zeny on the PC** (guarded by `confirmMutating`)\n\n---\n\n**Mutating — the owner's own statement.** Records that the owner saved the recovery key (the window's **I saved the key**); it removes the \"save your key\" reminder. Only the owner should send it, after actually saving the key offline. No body. Answer: the backup status. LAN: `403 BACKUP_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5w."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"fa58e1a2b3c4d5e6f708192a3b4c5d7f","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"settings\": { \"enabled\": true, \"dailyAt\": \"02:00\" }, \"recoveryKey\": { \"status\": \"saved\", \"keyId\": \"rk_00000000\" } },\n  \"metadata\": {}\n}"}],"_postman_id":"41694792-78b4-bddc-1326-f9af9320d0b1"},{"name":"⚠ Backup archives in Google Drive (calls Google Drive)","id":"aac5c1f7-a408-8099-dd03-34af78345d9f","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/backup/archives","description":"<p><strong>Local, this PC only</strong> · <code>GET {{baseUrl}}/api/v1/backup/archives</code> · Bearer (collection auth) · <strong>External read: lists the organization's backups in the connected Drive</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p>Nothing changes. Each archive: Drive file id (use it as <code>backupDriveFileId</code>), name, size, created time, organization tag, source PC. Without a Google connection a refusal. LAN: <code>403 BACKUP_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5w.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","backup","archives"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"3163cdaf-64be-1379-57ec-aacaf8a53fb1","name":"200 – two backups in Drive (synthetic)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/backup/archives","description":"**Local, this PC only** · `GET {{baseUrl}}/api/v1/backup/archives` · Bearer (collection auth) · **External read: lists the organization's backups in the connected Drive** (guarded by `confirmMutating`)\n\n---\n\nNothing changes. Each archive: Drive file id (use it as `backupDriveFileId`), name, size, created time, organization tag, source PC. Without a Google connection a refusal. LAN: `403 BACKUP_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` section 5w."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"0b69f2b3c4d5e6f708192a3b4c5d6e80","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    { \"driveFileId\": \"1DriveFileIdExample0000000000000001\", \"name\": \"AI Zeny backup 2026-10-18 0200.azbk\", \"bytes\": 81920, \"createdUtc\": \"2026-10-18T02:00:40Z\", \"organization\": \"org_example\", \"sourcePc\": \"EXAMPLE-PC\" },\n    { \"driveFileId\": \"1DriveFileIdExample0000000000000002\", \"name\": \"AI Zeny backup 2026-10-17 0200.azbk\", \"bytes\": 80896, \"createdUtc\": \"2026-10-17T02:00:38Z\", \"organization\": \"org_example\", \"sourcePc\": \"EXAMPLE-PC\" }\n  ],\n  \"metadata\": {}\n}"}],"_postman_id":"aac5c1f7-a408-8099-dd03-34af78345d9f"},{"name":"⚠⚠ Restore – upload an archive (.azbk)","id":"1064cb0f-9858-3bc4-24a4-9af6941d1e87","request":{"method":"POST","header":[{"value":"application/octet-stream","key":"Content-Type"}],"body":{"mode":"file","file":{}},"url":"{{baseUrl}}/api/v1/backup/restore/upload","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/backup/restore/upload</code> · Bearer (collection auth) · <strong>HIGH IMPACT: first step of a restore</strong>. Keep the existing <code>confirmMutating=yes</code> and <code>confirmHighImpact=POST /api/v1/backup/restore/upload</code> one-send guards. Do not send without separate owner approval and a verified backup.</p>\n<p>Choose a nonempty synthetic <code>.azbk</code> file in Postman's binary body; the pre-send guard checks that a local file source is selected. Send its bytes as exact <code>application/octet-stream</code> (maximum 2 GiB). Before an <strong>ordinary success</strong> send, independently measure that selected file and set <code>backupUploadExpectedBytes</code> to its positive decimal byte length in a local/temporary variable. The test compares the returned <code>bytes</code> with this fixture; Postman cannot infer the selected file's length from its response. A valid 200 is <code>{success:true,data:{uploadId,bytes},metadata:{}}</code>; only that verified receipt sets <code>backupUploadId</code>. Upload stages bytes in the Host work folder; it does <strong>not</strong> prepare or apply a restore. A syntactically successful upload is not archive-validation proof; validation occurs at prepare.</p>\n<p>For a deliberately expected refusal, set <code>fl6ExpectedRefusal_1064cb0f</code> to the exact <code>STATUS ERROR_CODE</code>, for example <code>400 BAD_REQUEST</code> for wrong Content-Type. That scenario requires the exact status, code and failure envelope. Unset the selector for ordinary success. An unexpected refusal, malformed 200 or no response never replaces an existing <code>backupUploadId</code>. Synthetic examples are contract illustrations, not live evidence. Option B is source-implemented: empty bytes return <code>400 BACKUP_ARCHIVE_UNSUPPORTED</code>; at most two in-flight or unused local uploads and 4 GiB actual aggregate bytes are allowed (<code>409 RESTORE_UPLOAD_QUOTA</code>). An unused upload expires two hours after completion (<code>410 RESTORE_UPLOAD_EXPIRED</code> if later named by prepare); a source already consumed by prepare returns <code>410 RESTORE_UPLOAD_CONSUMED</code> while its outcome is retained by this Host. After a Host restart old IDs are unavailable. Cleanup runs at the next upload or prepare and at orderly disposal, with marked orphan cleanup on the first new upload after restart; no background timer. Retain any uncertain ID for investigation, never assume it is reusable or blindly retry. Installed acceptance remains pending. See <code>docs/LOCAL-API.md</code> §5w.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","backup","restore","upload"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"fd743a53-a150-f2e3-f4a4-49e7b9c96af3","name":"SYNTHETIC — 200 staged upload; bytes match selected file","originalRequest":{"method":"POST","header":[],"url":"[object Object]","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/backup/restore/upload` · Bearer (collection auth) · **HIGH IMPACT: first step of a restore**. Keep the existing `confirmMutating=yes` and `confirmHighImpact=POST /api/v1/backup/restore/upload` one-send guards. Do not send without separate owner approval and a verified backup.\n\nChoose a synthetic `.azbk` file in Postman's binary body; send its bytes as exact `application/octet-stream` (maximum 2 GiB). Before an **ordinary success** send, independently measure that selected file and set `backupUploadExpectedBytes` to its positive decimal byte length in a local/temporary variable. The test compares the returned `bytes` with this fixture; Postman cannot infer the selected file's length from its response. A valid 200 is `{success:true,data:{uploadId,bytes},metadata:{}}`; only that verified receipt sets `backupUploadId`. Upload stages bytes in the Host work folder; it does **not** prepare or apply a restore. A syntactically successful upload is not archive-validation proof; validation occurs at prepare.\n\nFor a deliberately expected refusal, set `fl6ExpectedRefusal_1064cb0f` to the exact `STATUS ERROR_CODE`, for example `400 BAD_REQUEST` for wrong Content-Type. That scenario requires the exact status, code and failure envelope. Unset the selector for ordinary success. An unexpected refusal, malformed 200 or no response never replaces an existing `backupUploadId`. Synthetic examples are contract illustrations, not live evidence. Existing temporary-upload cleanup and empty-file policy remain separate open FL-28 work. See `docs/LOCAL-API.md` §5w."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"1c7a03c4d5e6f708192a3b4c5d6e7f91"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"uploadId\": \"upl_000000000000000000000000\",\n    \"bytes\": 81920\n  },\n  \"metadata\": {}\n}"},{"id":"7daf1dd3-65bf-e80f-2df4-cd999be344e6","name":"SYNTHETIC — 400 BAD_REQUEST wrong Content-Type; ID retained","originalRequest":{"method":"POST","header":[],"url":"[object Object]","description":"SYNTHETIC expected-refusal illustration: wrong Content-Type. Do not send for documentation verification."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BAD_REQUEST\",\n      \"message\": \"Send the backup file as application/octet-stream.\"\n    },\n    \"requestId\": \"22222222222222222222222222222222\"\n  }\n}"},{"id":"f2027ff3-b854-ff66-7f88-6b666c191212","name":"SYNTHETIC — 400 empty archive refused; no upload ID","originalRequest":{"method":"POST","header":[{"value":"application/octet-stream","key":"Content-Type"}],"body":{"mode":"file","file":{}},"url":"{{baseUrl}}/api/v1/backup/restore/upload","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/backup/restore/upload` · Bearer (collection auth) · **HIGH IMPACT: first step of a restore**. Keep the existing `confirmMutating=yes` and `confirmHighImpact=POST /api/v1/backup/restore/upload` one-send guards. Do not send without separate owner approval and a verified backup.\n\nChoose a nonempty synthetic `.azbk` file in Postman's binary body; the pre-send guard checks that a local file source is selected. Send its bytes as exact `application/octet-stream` (maximum 2 GiB). Before an **ordinary success** send, independently measure that selected file and set `backupUploadExpectedBytes` to its positive decimal byte length in a local/temporary variable. The test compares the returned `bytes` with this fixture; Postman cannot infer the selected file's length from its response. A valid 200 is `{success:true,data:{uploadId,bytes},metadata:{}}`; only that verified receipt sets `backupUploadId`. Upload stages bytes in the Host work folder; it does **not** prepare or apply a restore. A syntactically successful upload is not archive-validation proof; validation occurs at prepare.\n\nFor a deliberately expected refusal, set `fl6ExpectedRefusal_1064cb0f` to the exact `STATUS ERROR_CODE`, for example `400 BAD_REQUEST` for wrong Content-Type. That scenario requires the exact status, code and failure envelope. Unset the selector for ordinary success. An unexpected refusal, malformed 200 or no response never replaces an existing `backupUploadId`. Synthetic examples are contract illustrations, not live evidence. Option B is source-implemented: empty bytes return `400 BACKUP_ARCHIVE_UNSUPPORTED`; at most two in-flight or unused local uploads and 4 GiB actual aggregate bytes are allowed (`409 RESTORE_UPLOAD_QUOTA`). An unused upload expires two hours after completion (`410 RESTORE_UPLOAD_EXPIRED` if later named by prepare); a source already consumed by prepare returns `410 RESTORE_UPLOAD_CONSUMED` while its outcome is retained by this Host. After a Host restart old IDs are unavailable. Cleanup runs at the next upload or prepare and at orderly disposal, with marked orphan cleanup on the first new upload after restart; no background timer. Retain any uncertain ID for investigation, never assume it is reusable or blindly retry. Installed acceptance remains pending. See `docs/LOCAL-API.md` §5w."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BACKUP_ARCHIVE_UNSUPPORTED\",\n      \"message\": \"The selected backup file is empty. Choose a non-empty AI Zeny .azbk archive and upload it again.\"\n    },\n    \"requestId\": \"22222222222222222222222222222222\"\n  }\n}"},{"id":"0fa5d7c2-0514-3002-0d21-fd9f35b8d5ef","name":"SYNTHETIC — 409 active/unused upload quota; prior IDs retained","originalRequest":{"method":"POST","header":[{"value":"application/octet-stream","key":"Content-Type"}],"body":{"mode":"file","file":{}},"url":"{{baseUrl}}/api/v1/backup/restore/upload","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/backup/restore/upload` · Bearer (collection auth) · **HIGH IMPACT: first step of a restore**. Keep the existing `confirmMutating=yes` and `confirmHighImpact=POST /api/v1/backup/restore/upload` one-send guards. Do not send without separate owner approval and a verified backup.\n\nChoose a nonempty synthetic `.azbk` file in Postman's binary body; the pre-send guard checks that a local file source is selected. Send its bytes as exact `application/octet-stream` (maximum 2 GiB). Before an **ordinary success** send, independently measure that selected file and set `backupUploadExpectedBytes` to its positive decimal byte length in a local/temporary variable. The test compares the returned `bytes` with this fixture; Postman cannot infer the selected file's length from its response. A valid 200 is `{success:true,data:{uploadId,bytes},metadata:{}}`; only that verified receipt sets `backupUploadId`. Upload stages bytes in the Host work folder; it does **not** prepare or apply a restore. A syntactically successful upload is not archive-validation proof; validation occurs at prepare.\n\nFor a deliberately expected refusal, set `fl6ExpectedRefusal_1064cb0f` to the exact `STATUS ERROR_CODE`, for example `400 BAD_REQUEST` for wrong Content-Type. That scenario requires the exact status, code and failure envelope. Unset the selector for ordinary success. An unexpected refusal, malformed 200 or no response never replaces an existing `backupUploadId`. Synthetic examples are contract illustrations, not live evidence. Option B is source-implemented: empty bytes return `400 BACKUP_ARCHIVE_UNSUPPORTED`; at most two in-flight or unused local uploads and 4 GiB actual aggregate bytes are allowed (`409 RESTORE_UPLOAD_QUOTA`). An unused upload expires two hours after completion (`410 RESTORE_UPLOAD_EXPIRED` if later named by prepare); a source already consumed by prepare returns `410 RESTORE_UPLOAD_CONSUMED` while its outcome is retained by this Host. After a Host restart old IDs are unavailable. Cleanup runs at the next upload or prepare and at orderly disposal, with marked orphan cleanup on the first new upload after restart; no background timer. Retain any uncertain ID for investigation, never assume it is reusable or blindly retry. Installed acceptance remains pending. See `docs/LOCAL-API.md` §5w."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"RESTORE_UPLOAD_QUOTA\",\n      \"message\": \"At most two restore uploads totaling 4 GiB may be active or waiting. Prepare an existing upload or wait for it to expire before uploading again.\"\n    },\n    \"requestId\": \"22222222222222222222222222222222\"\n  }\n}"},{"id":"fbca6c09-358f-0b39-efc9-10d8b4ec00cd","name":"SYNTHETIC — 503 upload workspace unavailable; do not retry blindly","originalRequest":{"method":"POST","header":[{"value":"application/octet-stream","key":"Content-Type"}],"body":{"mode":"file","file":{}},"url":"{{baseUrl}}/api/v1/backup/restore/upload","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/backup/restore/upload` · Bearer (collection auth) · **HIGH IMPACT: first step of a restore**. Keep the existing `confirmMutating=yes` and `confirmHighImpact=POST /api/v1/backup/restore/upload` one-send guards. Do not send without separate owner approval and a verified backup.\n\nChoose a nonempty synthetic `.azbk` file in Postman's binary body; the pre-send guard checks that a local file source is selected. Send its bytes as exact `application/octet-stream` (maximum 2 GiB). Before an **ordinary success** send, independently measure that selected file and set `backupUploadExpectedBytes` to its positive decimal byte length in a local/temporary variable. The test compares the returned `bytes` with this fixture; Postman cannot infer the selected file's length from its response. A valid 200 is `{success:true,data:{uploadId,bytes},metadata:{}}`; only that verified receipt sets `backupUploadId`. Upload stages bytes in the Host work folder; it does **not** prepare or apply a restore. A syntactically successful upload is not archive-validation proof; validation occurs at prepare.\n\nFor a deliberately expected refusal, set `fl6ExpectedRefusal_1064cb0f` to the exact `STATUS ERROR_CODE`, for example `400 BAD_REQUEST` for wrong Content-Type. That scenario requires the exact status, code and failure envelope. Unset the selector for ordinary success. An unexpected refusal, malformed 200 or no response never replaces an existing `backupUploadId`. Synthetic examples are contract illustrations, not live evidence. Option B is source-implemented: empty bytes return `400 BACKUP_ARCHIVE_UNSUPPORTED`; at most two in-flight or unused local uploads and 4 GiB actual aggregate bytes are allowed (`409 RESTORE_UPLOAD_QUOTA`). An unused upload expires two hours after completion (`410 RESTORE_UPLOAD_EXPIRED` if later named by prepare); a source already consumed by prepare returns `410 RESTORE_UPLOAD_CONSUMED` while its outcome is retained by this Host. After a Host restart old IDs are unavailable. Cleanup runs at the next upload or prepare and at orderly disposal, with marked orphan cleanup on the first new upload after restart; no background timer. Retain any uncertain ID for investigation, never assume it is reusable or blindly retry. Installed acceptance remains pending. See `docs/LOCAL-API.md` §5w."},"status":"Service Unavailable","code":503,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"RESTORE_UPLOAD_UNAVAILABLE\",\n      \"message\": \"Restore uploads are unavailable on this PC. Check that no other Host owns the upload workspace, then try again.\"\n    },\n    \"requestId\": \"22222222222222222222222222222222\"\n  }\n}"}],"_postman_id":"1064cb0f-9858-3bc4-24a4-9af6941d1e87"},{"name":"⚠⚠ Restore – prepare (verify and preview)","id":"915f5cf3-fdaa-d0e0-63da-1773eed70c62","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"driveFileId\": \"{{backupDriveFileId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/backup/restore/prepare","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/backup/restore/prepare</code> · Bearer (collection auth) · <strong>HIGH IMPACT: reads, decrypts and stages a backup</strong>. Keep the existing <code>confirmMutating=yes</code> and <code>confirmHighImpact=POST /api/v1/backup/restore/prepare</code> one-send guards. Do not send without separate owner approval.</p>\n<p>Body: exactly one nonempty <code>driveFileId</code> or <code>uploadId</code>, with optional <code>recoveryKey</code> in the body only. The saved example uses <code>backupDriveFileId</code>; when intentionally using a previously uploaded synthetic archive, change the body to <code>{ \"uploadId\": \"{{backupUploadId}}\" }</code>. A recovery key is needed only when this PC's existing key cannot open the archive. Do not print or save it in a shared example.</p>\n<p>Prepare is <strong>not a read-only/no-effect operation</strong>. For a Drive source it downloads a temporary archive; for an upload source it reads the staged upload. It checks and decrypts the archive, writes/migrates staged database copies, and holds a successful prepared object for <strong>30 minutes</strong>. A processed <code>uploadId</code> and its temporary file are removed in <code>finally</code> on success <strong>or a later refusal</strong>; earlier validation can refuse before that point. An unused local upload expires two hours after completion; prepare naming it returns <code>410 RESTORE_UPLOAD_EXPIRED</code>. Prepare consumes a claimed upload on success or later refusal; repeating its ID can return <code>410 RESTORE_UPLOAD_CONSUMED</code>. An ID from before a Host restart returns actionable <code>404 RESTORE_NOT_FOUND</code>. A refusal or timeout does not prove a retained ID remains reusable. Temporary Drive downloads are removed. <strong>Live settings and messaging databases are not replaced by prepare</strong>; apply schedules their later replacement. Use restore/discard for a verified prepared ID that you decide not to apply.</p>\n<p>Ordinary success requires exact 200 and the full eleven-field preview: <code>restoreId,archiveId,createdUtc,productVersion,fromThisPc,googleAccount,googleAccountDiffers,contents,restores,needsAttention,expiresUtc</code>, within <code>{success:true,data,metadata:{}}</code>. Only a fully checked success saves <code>backupRestoreId</code> and clears a matching consumed <code>backupUploadId</code>. For a deliberately expected refusal, set <code>fl6ExpectedRefusal_915f5cf3</code> to exact <code>STATUS ERROR_CODE</code> before Send (for example <code>409 GOOGLE_NOT_CONNECTED</code> for a Drive source or <code>400 BACKUP_ARCHIVE_CORRUPT</code> for a damaged uploaded source); unset it for ordinary success. Refusal tests require the exact status/code/failure envelope. The pre-send script marks <code>restorePreparePendingReview=yes</code>; refusal, malformed/unexpected response or timeout keeps the existing IDs and that marker. Inspect the source/staging state before manually clearing it. Never blindly resend an uncertain prepare. All response examples are synthetic contract illustrations, not live evidence. See <code>docs/LOCAL-API.md</code> §5w.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","backup","restore","prepare"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"7d850ec0-45db-e20f-0fb9-fdc0bdb584ee","name":"SYNTHETIC — 200 verified preview; staging held 30 minutes","originalRequest":{"method":"POST","header":[],"url":"[object Object]","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/backup/restore/prepare` · Bearer (collection auth) · **HIGH IMPACT: reads, decrypts and stages a backup**. Keep the existing `confirmMutating=yes` and `confirmHighImpact=POST /api/v1/backup/restore/prepare` one-send guards. Do not send without separate owner approval.\n\nBody: exactly one nonempty `driveFileId` or `uploadId`, with optional `recoveryKey` in the body only. The saved example uses `backupDriveFileId`; when intentionally using a previously uploaded synthetic archive, change the body to `{ \"uploadId\": \"{{backupUploadId}}\" }`. A recovery key is needed only when this PC's existing key cannot open the archive. Do not print or save it in a shared example.\n\nPrepare is **not a read-only/no-effect operation**. For a Drive source it downloads a temporary archive; for an upload source it reads the staged upload. It checks and decrypts the archive, writes/migrates staged database copies, and holds a successful prepared object for **30 minutes**. A processed `uploadId` and its temporary file are removed in `finally` on success **or a later refusal**; earlier validation can refuse before that point. A refusal or timeout therefore does not prove the upload ID remains reusable. Temporary Drive downloads are removed. **Live settings and messaging databases are not replaced by prepare**; apply schedules their later replacement. Use restore/discard for a verified prepared ID that you decide not to apply.\n\nOrdinary success requires exact 200 and the full eleven-field preview: `restoreId,archiveId,createdUtc,productVersion,fromThisPc,googleAccount,googleAccountDiffers,contents,restores,needsAttention,expiresUtc`, within `{success:true,data,metadata:{}}`. Only a fully checked success saves `backupRestoreId` and clears a matching consumed `backupUploadId`. For a deliberately expected refusal, set `fl6ExpectedRefusal_915f5cf3` to exact `STATUS ERROR_CODE` before Send (for example `409 GOOGLE_NOT_CONNECTED` for a Drive source or `400 BACKUP_ARCHIVE_CORRUPT` for a damaged uploaded source); unset it for ordinary success. Refusal tests require the exact status/code/failure envelope. The pre-send script marks `restorePreparePendingReview=yes`; refusal, malformed/unexpected response or timeout keeps the existing IDs and that marker. Inspect the source/staging state before manually clearing it. Never blindly resend an uncertain prepare. All response examples are synthetic contract illustrations, not live evidence. See `docs/LOCAL-API.md` §5w."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"2d8b14d5e6f708192a3b4c5d6e7f80a2"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"restoreId\": \"rst_000000000000000000000000\",\n    \"archiveId\": \"11111111111111111111111111111111\",\n    \"createdUtc\": \"2026-10-20T01:02:03Z\",\n    \"productVersion\": \"0.0.16\",\n    \"fromThisPc\": true,\n    \"googleAccount\": null,\n    \"googleAccountDiffers\": false,\n    \"contents\": {\n      \"settingsRecords\": 16,\n      \"companies\": 2,\n      \"companyPasswords\": 0,\n      \"savedQueries\": 1,\n      \"scripts\": 1,\n      \"scriptAssignments\": 1,\n      \"schedules\": 0,\n      \"scheduleParameters\": 0,\n      \"emailMessages\": 0,\n      \"whatsAppMessages\": 0,\n      \"secretsNotCarried\": 0,\n      \"sheetExports\": 1\n    },\n    \"restores\": [\n      \"2 BUSY company connections\",\n      \"1 custom query\",\n      \"1 script and 1 company assignment\",\n      \"0 schedules\",\n      \"1 Google Sheets export\",\n      \"0 Email or WhatsApp history rows\",\n      \"AI Zeny settings such as the backup time\"\n    ],\n    \"needsAttention\": [\n      \"Check each BUSY company with Test connection: the BUSY data folder or SQL Server must exist on this PC.\",\n      \"Google Sheets exports wait until the Google account each one was set up with is connected on this PC; their run history starts again.\",\n      \"Schedule run history and the Local API log are not restored; they start again.\"\n    ],\n    \"expiresUtc\": \"2026-10-21T01:32:03Z\"\n  },\n  \"metadata\": {}\n}"},{"id":"49f4a228-4b51-f62f-505c-bff47893c922","name":"SYNTHETIC — 409 GOOGLE_NOT_CONNECTED; Drive source refused","originalRequest":{"method":"POST","header":[],"url":"[object Object]","description":"SYNTHETIC expected refusal: Drive source is unavailable. Do not send for documentation verification."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"GOOGLE_NOT_CONNECTED\",\n      \"message\": \"Sign in to Google with the account that holds the backups first.\"\n    },\n    \"requestId\": \"22222222222222222222222222222222\"\n  }\n}"},{"id":"e5582762-c973-2fc2-4e9d-ae5bdae6da6f","name":"SYNTHETIC — 400 BACKUP_ARCHIVE_CORRUPT; uploaded source may be consumed","originalRequest":{"method":"POST","header":[],"url":"[object Object]","description":"SYNTHETIC expected refusal: damaged uploaded source; it may be consumed. Do not send for documentation verification."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BACKUP_ARCHIVE_CORRUPT\",\n      \"message\": \"The backup file is damaged or was changed.\"\n    },\n    \"requestId\": \"22222222222222222222222222222222\"\n  }\n}"},{"id":"ec5fda05-48f6-70ce-6249-64188f4a37d6","name":"SYNTHETIC — 410 unused upload expired; re-upload after review","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"driveFileId\": \"{{backupDriveFileId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/backup/restore/prepare","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/backup/restore/prepare` · Bearer (collection auth) · **HIGH IMPACT: reads, decrypts and stages a backup**. Keep the existing `confirmMutating=yes` and `confirmHighImpact=POST /api/v1/backup/restore/prepare` one-send guards. Do not send without separate owner approval.\n\nBody: exactly one nonempty `driveFileId` or `uploadId`, with optional `recoveryKey` in the body only. The saved example uses `backupDriveFileId`; when intentionally using a previously uploaded synthetic archive, change the body to `{ \"uploadId\": \"{{backupUploadId}}\" }`. A recovery key is needed only when this PC's existing key cannot open the archive. Do not print or save it in a shared example.\n\nPrepare is **not a read-only/no-effect operation**. For a Drive source it downloads a temporary archive; for an upload source it reads the staged upload. It checks and decrypts the archive, writes/migrates staged database copies, and holds a successful prepared object for **30 minutes**. A processed `uploadId` and its temporary file are removed in `finally` on success **or a later refusal**; earlier validation can refuse before that point. An unused local upload expires two hours after completion; prepare naming it returns `410 RESTORE_UPLOAD_EXPIRED`. Prepare consumes a claimed upload on success or later refusal; repeating its ID can return `410 RESTORE_UPLOAD_CONSUMED`. An ID from before a Host restart returns actionable `404 RESTORE_NOT_FOUND`. A refusal or timeout does not prove a retained ID remains reusable. Temporary Drive downloads are removed. **Live settings and messaging databases are not replaced by prepare**; apply schedules their later replacement. Use restore/discard for a verified prepared ID that you decide not to apply.\n\nOrdinary success requires exact 200 and the full eleven-field preview: `restoreId,archiveId,createdUtc,productVersion,fromThisPc,googleAccount,googleAccountDiffers,contents,restores,needsAttention,expiresUtc`, within `{success:true,data,metadata:{}}`. Only a fully checked success saves `backupRestoreId` and clears a matching consumed `backupUploadId`. For a deliberately expected refusal, set `fl6ExpectedRefusal_915f5cf3` to exact `STATUS ERROR_CODE` before Send (for example `409 GOOGLE_NOT_CONNECTED` for a Drive source or `400 BACKUP_ARCHIVE_CORRUPT` for a damaged uploaded source); unset it for ordinary success. Refusal tests require the exact status/code/failure envelope. The pre-send script marks `restorePreparePendingReview=yes`; refusal, malformed/unexpected response or timeout keeps the existing IDs and that marker. Inspect the source/staging state before manually clearing it. Never blindly resend an uncertain prepare. All response examples are synthetic contract illustrations, not live evidence. See `docs/LOCAL-API.md` §5w."},"status":"Gone","code":410,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"RESTORE_UPLOAD_EXPIRED\",\n      \"message\": \"That uploaded file expired after two hours. Choose the archive and upload it again.\"\n    },\n    \"requestId\": \"22222222222222222222222222222222\"\n  }\n}"},{"id":"32b8804b-52eb-d2f0-4f77-60ffd6baf8c9","name":"SYNTHETIC — 410 uploaded source consumed by prepare","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"driveFileId\": \"{{backupDriveFileId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/backup/restore/prepare","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/backup/restore/prepare` · Bearer (collection auth) · **HIGH IMPACT: reads, decrypts and stages a backup**. Keep the existing `confirmMutating=yes` and `confirmHighImpact=POST /api/v1/backup/restore/prepare` one-send guards. Do not send without separate owner approval.\n\nBody: exactly one nonempty `driveFileId` or `uploadId`, with optional `recoveryKey` in the body only. The saved example uses `backupDriveFileId`; when intentionally using a previously uploaded synthetic archive, change the body to `{ \"uploadId\": \"{{backupUploadId}}\" }`. A recovery key is needed only when this PC's existing key cannot open the archive. Do not print or save it in a shared example.\n\nPrepare is **not a read-only/no-effect operation**. For a Drive source it downloads a temporary archive; for an upload source it reads the staged upload. It checks and decrypts the archive, writes/migrates staged database copies, and holds a successful prepared object for **30 minutes**. A processed `uploadId` and its temporary file are removed in `finally` on success **or a later refusal**; earlier validation can refuse before that point. An unused local upload expires two hours after completion; prepare naming it returns `410 RESTORE_UPLOAD_EXPIRED`. Prepare consumes a claimed upload on success or later refusal; repeating its ID can return `410 RESTORE_UPLOAD_CONSUMED`. An ID from before a Host restart returns actionable `404 RESTORE_NOT_FOUND`. A refusal or timeout does not prove a retained ID remains reusable. Temporary Drive downloads are removed. **Live settings and messaging databases are not replaced by prepare**; apply schedules their later replacement. Use restore/discard for a verified prepared ID that you decide not to apply.\n\nOrdinary success requires exact 200 and the full eleven-field preview: `restoreId,archiveId,createdUtc,productVersion,fromThisPc,googleAccount,googleAccountDiffers,contents,restores,needsAttention,expiresUtc`, within `{success:true,data,metadata:{}}`. Only a fully checked success saves `backupRestoreId` and clears a matching consumed `backupUploadId`. For a deliberately expected refusal, set `fl6ExpectedRefusal_915f5cf3` to exact `STATUS ERROR_CODE` before Send (for example `409 GOOGLE_NOT_CONNECTED` for a Drive source or `400 BACKUP_ARCHIVE_CORRUPT` for a damaged uploaded source); unset it for ordinary success. Refusal tests require the exact status/code/failure envelope. The pre-send script marks `restorePreparePendingReview=yes`; refusal, malformed/unexpected response or timeout keeps the existing IDs and that marker. Inspect the source/staging state before manually clearing it. Never blindly resend an uncertain prepare. All response examples are synthetic contract illustrations, not live evidence. See `docs/LOCAL-API.md` §5w."},"status":"Gone","code":410,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"RESTORE_UPLOAD_CONSUMED\",\n      \"message\": \"Prepare already consumed that uploaded file. Check the earlier outcome before choosing and uploading it again.\"\n    },\n    \"requestId\": \"22222222222222222222222222222222\"\n  }\n}"}],"_postman_id":"915f5cf3-fdaa-d0e0-63da-1773eed70c62"},{"name":"⚠⚠ Restore – APPLY (schedules replacement at Host restart)","id":"014d2a3b-edf2-60e8-514a-cd16b56b3076","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"restoreId\": \"{{backupRestoreId}}\",\n  \"confirm\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/backup/restore/apply","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/backup/restore/apply</code> · Bearer (collection auth) · <strong>HIGHEST IMPACT:</strong> schedules replacement of AI Zeny's settings and message history on this PC. Keep the existing <code>confirmMutating=yes</code> and <code>confirmHighImpact=POST /api/v1/backup/restore/apply</code> one-send guards. Never run without the owner's explicit, separate approval and a verified data-root backup.</p>\n<p>Body: <code>{ \"restoreId\": \"{{backupRestoreId}}\", \"confirm\": true }</code>. The prepared ID comes from restore/prepare and expires after 30 minutes. This PC only; never relayed. A valid <strong>200 means the restore was recorded for Host restart</strong>, not that live databases have already changed. Before returning, the Host rehearses changes on staged copies, may adopt a recovery key, records a pending restore and requests a restart. At the next Host startup it takes the reserved <code>pre-restore-*</code> safety copy and applies settings and messaging tables. Startup can fail or retry; verify the subsequent Host/recovery status separately before claiming the restore completed. The 200 <code>data</code> is <code>{archiveId, restored, secretsResealed, secretsToEnterAgain, safetyCopy, recoveryKeyAdopted, hostRestarts:true, needsAttention}</code>; <code>restored</code> is the backup's content counts, not proof that live tables were already replaced. <code>metadata</code> is <code>{}</code>.</p>\n<p>Ordinary success requires exact 200 and the complete scheduled-result shape. For a deliberate refusal set <code>fl6ExpectedRefusal_014d2a3b</code> to exactly <code>STATUS ERROR_CODE</code> before Send, for example <code>404 RESTORE_NOT_FOUND</code> or <code>400 RESTORE_NOT_CONFIRMED</code>; exact status, code and failure envelope are required. Synthetic examples are illustrations, not live evidence. A refusal, malformed 200, unexpected status or no response <strong>never clears</strong> <code>backupRestoreId</code>. The pre-send script marks <code>restoreApplyPendingReview=yes</code>; only a verified scheduled 200 clears the marker and prepared ID. After any other outcome, inspect Host/pending restore state before manually resetting the review marker. Some refusals occur after the service consumes the prepared ID (for example a backup-running <code>409 RESTORE_BUSY</code>); retaining the Postman variable does not prove that ID can be reused. Never blindly resend. A 200 scheduled result also consumes the prepared ID, which is why the script clears it only after every documented result field verifies.</p>\n<p>The <code>safetyCopy</code> response member is the <strong>reserved name</strong>, not proof that the copy has been taken; the copy is made on startup. Enrollment, Local API token, runtime history and BUSY databases are not replaced by this restore. See <code>docs/LOCAL-API.md</code> §5w and <code>docs/public/google/backup-and-restore.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","backup","restore","apply"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"fc4f1d43-8648-7fed-8547-10c3eeb910bd","name":"SYNTHETIC — 200 scheduled for Host restart; not yet applied","originalRequest":{"method":"POST","header":[],"url":"[object Object]","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/backup/restore/apply` · Bearer (collection auth) · **HIGHEST IMPACT:** schedules replacement of AI Zeny's settings and message history on this PC. Keep the existing `confirmMutating=yes` and `confirmHighImpact=POST /api/v1/backup/restore/apply` one-send guards. Never run without the owner's explicit, separate approval and a verified data-root backup.\n\nBody: `{ \"restoreId\": \"{{backupRestoreId}}\", \"confirm\": true }`. The prepared ID comes from restore/prepare and expires after 30 minutes. This PC only; never relayed. A valid **200 means the restore was recorded for Host restart**, not that live databases have already changed. Before returning, the Host rehearses changes on staged copies, may adopt a recovery key, records a pending restore and requests a restart. At the next Host startup it takes the reserved `pre-restore-*` safety copy and applies settings and messaging tables. Startup can fail or retry; verify the subsequent Host/recovery status separately before claiming the restore completed. The 200 `data` is `{archiveId, restored, secretsResealed, secretsToEnterAgain, safetyCopy, recoveryKeyAdopted, hostRestarts:true, needsAttention}`; `restored` is the backup's content counts, not proof that live tables were already replaced. `metadata` is `{}`.\n\nOrdinary success requires exact 200 and the complete scheduled-result shape. For a deliberate refusal set `fl6ExpectedRefusal_014d2a3b` to exactly `STATUS ERROR_CODE` before Send, for example `404 RESTORE_NOT_FOUND` or `400 RESTORE_NOT_CONFIRMED`; exact status, code and failure envelope are required. Synthetic examples are illustrations, not live evidence. A refusal, malformed 200, unexpected status or no response **never clears** `backupRestoreId`. The pre-send script marks `restoreApplyPendingReview=yes`; only a verified scheduled 200 clears the marker and prepared ID. After any other outcome, inspect Host/pending restore state before manually resetting the review marker. Some refusals occur after the service consumes the prepared ID (for example a backup-running `409 RESTORE_BUSY`); retaining the Postman variable does not prove that ID can be reused. Never blindly resend. A 200 scheduled result also consumes the prepared ID, which is why the script clears it only after every documented result field verifies.\n\nThe `safetyCopy` response member is the **reserved name**, not proof that the copy has been taken; the copy is made on startup. Enrollment, Local API token, runtime history and BUSY databases are not replaced by this restore. See `docs/LOCAL-API.md` §5w and `docs/public/google/backup-and-restore.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"3e9c25e6f708192a3b4c5d6e7f8091b3","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"archiveId\": \"11111111111111111111111111111111\",\n    \"restored\": {\n      \"settingsRecords\": 16,\n      \"companies\": 2,\n      \"companyPasswords\": 0,\n      \"savedQueries\": 1,\n      \"scripts\": 1,\n      \"scriptAssignments\": 1,\n      \"schedules\": 0,\n      \"scheduleParameters\": 0,\n      \"emailMessages\": 0,\n      \"whatsAppMessages\": 0,\n      \"secretsNotCarried\": 0,\n      \"sheetExports\": 1\n    },\n    \"secretsResealed\": 0,\n    \"secretsToEnterAgain\": 0,\n    \"safetyCopy\": \"pre-restore-20261021T010203Z\",\n    \"recoveryKeyAdopted\": false,\n    \"hostRestarts\": true,\n    \"needsAttention\": []\n  },\n  \"metadata\": {}\n}"},{"id":"8176c6c7-a18a-22ee-705a-5956e17a755e","name":"SYNTHETIC — 404 RESTORE_NOT_FOUND; prepared ID retained in Postman","originalRequest":{"method":"POST","header":[],"url":"[object Object]","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/backup/restore/apply` · Bearer (collection auth) · **HIGHEST IMPACT:** schedules replacement of AI Zeny's settings and message history on this PC. Keep the existing `confirmMutating=yes` and `confirmHighImpact=POST /api/v1/backup/restore/apply` one-send guards. Never run without the owner's explicit, separate approval and a verified data-root backup.\n\nBody: `{ \"restoreId\": \"{{backupRestoreId}}\", \"confirm\": true }`. The prepared ID comes from restore/prepare and expires after 30 minutes. This PC only; never relayed. A valid **200 means the restore was recorded for Host restart**, not that live databases have already changed. Before returning, the Host rehearses changes on staged copies, may adopt a recovery key, records a pending restore and requests a restart. At the next Host startup it takes the reserved `pre-restore-*` safety copy and applies settings and messaging tables. Startup can fail or retry; verify the subsequent Host/recovery status separately before claiming the restore completed. The 200 `data` is `{archiveId, restored, secretsResealed, secretsToEnterAgain, safetyCopy, recoveryKeyAdopted, hostRestarts:true, needsAttention}`; `restored` is the backup's content counts, not proof that live tables were already replaced. `metadata` is `{}`.\n\nOrdinary success requires exact 200 and the complete scheduled-result shape. For a deliberate refusal set `fl6ExpectedRefusal_014d2a3b` to exactly `STATUS ERROR_CODE` before Send, for example `404 RESTORE_NOT_FOUND` or `400 RESTORE_NOT_CONFIRMED`; exact status, code and failure envelope are required. Synthetic examples are illustrations, not live evidence. A refusal, malformed 200, unexpected status or no response **never clears** `backupRestoreId`. The pre-send script marks `restoreApplyPendingReview=yes`; only a verified scheduled 200 clears the marker and prepared ID. After any other outcome, inspect Host/pending restore state before manually resetting the review marker. Some refusals occur after the service consumes the prepared ID (for example a backup-running `409 RESTORE_BUSY`); retaining the Postman variable does not prove that ID can be reused. Never blindly resend. A 200 scheduled result also consumes the prepared ID, which is why the script clears it only after every documented result field verifies.\n\nThe `safetyCopy` response member is the **reserved name**, not proof that the copy has been taken; the copy is made on startup. Enrollment, Local API token, runtime history and BUSY databases are not replaced by this restore. See `docs/LOCAL-API.md` §5w and `docs/public/google/backup-and-restore.md`."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"RESTORE_NOT_FOUND\",\n      \"message\": \"That restore is no longer prepared. Open the backup again.\"\n    },\n    \"requestId\": \"22222222222222222222222222222222\"\n  }\n}"},{"id":"1346c2ec-8580-e6f8-db02-53501fbd85f0","name":"SYNTHETIC — 409 RESTORE_BUSY; prepared ID retained for review","originalRequest":{"method":"POST","header":[],"url":"[object Object]","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/backup/restore/apply` · Bearer (collection auth) · **HIGHEST IMPACT:** schedules replacement of AI Zeny's settings and message history on this PC. Keep the existing `confirmMutating=yes` and `confirmHighImpact=POST /api/v1/backup/restore/apply` one-send guards. Never run without the owner's explicit, separate approval and a verified data-root backup.\n\nBody: `{ \"restoreId\": \"{{backupRestoreId}}\", \"confirm\": true }`. The prepared ID comes from restore/prepare and expires after 30 minutes. This PC only; never relayed. A valid **200 means the restore was recorded for Host restart**, not that live databases have already changed. Before returning, the Host rehearses changes on staged copies, may adopt a recovery key, records a pending restore and requests a restart. At the next Host startup it takes the reserved `pre-restore-*` safety copy and applies settings and messaging tables. Startup can fail or retry; verify the subsequent Host/recovery status separately before claiming the restore completed. The 200 `data` is `{archiveId, restored, secretsResealed, secretsToEnterAgain, safetyCopy, recoveryKeyAdopted, hostRestarts:true, needsAttention}`; `restored` is the backup's content counts, not proof that live tables were already replaced. `metadata` is `{}`.\n\nOrdinary success requires exact 200 and the complete scheduled-result shape. For a deliberate refusal set `fl6ExpectedRefusal_014d2a3b` to exactly `STATUS ERROR_CODE` before Send, for example `404 RESTORE_NOT_FOUND` or `400 RESTORE_NOT_CONFIRMED`; exact status, code and failure envelope are required. Synthetic examples are illustrations, not live evidence. A refusal, malformed 200, unexpected status or no response **never clears** `backupRestoreId`. The pre-send script marks `restoreApplyPendingReview=yes`; only a verified scheduled 200 clears the marker and prepared ID. After any other outcome, inspect Host/pending restore state before manually resetting the review marker. Some refusals occur after the service consumes the prepared ID (for example a backup-running `409 RESTORE_BUSY`); retaining the Postman variable does not prove that ID can be reused. Never blindly resend. A 200 scheduled result also consumes the prepared ID, which is why the script clears it only after every documented result field verifies.\n\nThe `safetyCopy` response member is the **reserved name**, not proof that the copy has been taken; the copy is made on startup. Enrollment, Local API token, runtime history and BUSY databases are not replaced by this restore. See `docs/LOCAL-API.md` §5w and `docs/public/google/backup-and-restore.md`."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"RESTORE_BUSY\",\n      \"message\": \"A backup is running. Restore when it has finished.\"\n    },\n    \"requestId\": \"22222222222222222222222222222222\"\n  }\n}"}],"_postman_id":"014d2a3b-edf2-60e8-514a-cd16b56b3076"},{"name":"⚠ Restore – discard a prepared restore","id":"9260c5aa-6c46-48be-4e5a-d73286a9fc6d","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"restoreId\": \"{{backupRestoreId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/backup/restore/discard","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/backup/restore/discard</code> · Bearer (collection auth) · <strong>Changes AI Zeny on the PC</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Discards a prepared restore and its staging copy; nothing on the PC was replaced. Body <code>{ restoreId }</code>. Current 200 answer: <code>data: { uploadId: &lt;restoreId&gt;, bytes: 0 }</code>, <code>metadata: {}</code>; <code>uploadId</code> is the current shared receipt member name for the prepared restore ID. A missing/stale ID returns <code>404 RESTORE_NOT_FOUND</code> with <code>data: null</code> (separate refusal scenario). Skipped while <code>backupRestoreId</code> is empty.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5w.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","backup","restore","discard"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"52058567-a75d-e9a7-e0f0-57d276eef346","name":"200 – prepared restore discarded (synthetic)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"restoreId\": \"{{backupRestoreId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/backup/restore/discard","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/backup/restore/discard` · Bearer (collection auth) · **Changes AI Zeny on the PC** (guarded by `confirmMutating`)\n\n---\n\n**Mutating — run manually.** Discards a prepared restore and its staging copy; nothing on the PC was replaced. Body `{ restoreId }`. Current 200 answer: `data: { uploadId: <restoreId>, bytes: 0 }`, `metadata: {}`; `uploadId` is the current shared receipt member name for the prepared restore ID. A missing/stale ID returns `404 RESTORE_NOT_FOUND` with `data: null` (separate refusal scenario). Skipped while `backupRestoreId` is empty.\n\nContract: `docs/LOCAL-API.md` section 5w."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"4fad36f708192a3b4c5d6e7f8091a2c5"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"uploadId\": \"synthetic-restore-001\",\n    \"bytes\": 0\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"9260c5aa-6c46-48be-4e5a-d73286a9fc6d"}],"id":"bc807f0b-3197-ae46-7574-0ac428b9a5f1","_postman_id":"bc807f0b-3197-ae46-7574-0ac428b9a5f1","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ Security & Subscription — M-PIN recovery, plan check (this PC only)","item":[{"name":"⚠ Subscription – check the plan now (calls the AI Zeny cloud)","id":"bdedda75-e5d4-c6b5-c223-210357d82b08","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/subscription/refresh","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/subscription/refresh</code> · Bearer (collection auth) · <strong>External: asks the AI Zeny cloud for this PC's device state</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Run manually.</strong> The Overview's <strong>Refresh now</strong>: one authenticated <code>GET /v1/device/state</code> (credential rotation when due, refresh once on a 401; a running automatic check is joined). Stores the plan, status and limits; the next automatic check moves 4 hours later. A revoked, disabled or incompatible answer changes access exactly as the 4-hourly check would. No body. Answer: the enrollment summary (with <code>subscription.companyLimit</code> / <code>financialYearLimit</code>), <code>metadata</code> <code>{ joined, nextAutomaticCheckUtc }</code>. Failures keep the cached plan: <code>504 SUBSCRIPTION_REFRESH_TIMEOUT</code> (60 s) and fixed sentences. LAN: <code>403 SUBSCRIPTION_LOOPBACK_ONLY</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> (subscription refresh row); <code>docs/public/getting-started/overview.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","subscription","refresh"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"13520f13-9fba-d4eb-aeb2-d36ca1d4ca79","name":"200 – plan checked (synthetic)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/subscription/refresh","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/subscription/refresh` · Bearer (collection auth) · **External: asks the AI Zeny cloud for this PC's device state** (guarded by `confirmMutating`)\n\n---\n\n**Run manually.** The Overview's **Refresh now**: one authenticated `GET /v1/device/state` (credential rotation when due, refresh once on a 401; a running automatic check is joined). Stores the plan, status and limits; the next automatic check moves 4 hours later. A revoked, disabled or incompatible answer changes access exactly as the 4-hourly check would. No body. Answer: the enrollment summary (with `subscription.companyLimit` / `financialYearLimit`), `metadata` `{ joined, nextAutomaticCheckUtc }`. Failures keep the cached plan: `504 SUBSCRIPTION_REFRESH_TIMEOUT` (60 s) and fixed sentences. LAN: `403 SUBSCRIPTION_LOOPBACK_ONLY`.\n\nContract: `docs/LOCAL-API.md` (subscription refresh row); `docs/public/getting-started/overview.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"50be4708192a3b4c5d6e7f8091a2b3d6","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"state\": \"enrolled\",\n    \"organizationName\": \"Example Organization\",\n    \"organizationId\": \"org_example\",\n    \"subscription\": { \"plan\": \"pro\", \"status\": \"active\", \"periodEndUtc\": \"2027-10-02T07:57:00Z\", \"companyLimit\": 3, \"financialYearLimit\": 2, \"checkedUtc\": \"2026-10-18T06:15:00Z\" }\n  },\n  \"metadata\": { \"joined\": false, \"nextAutomaticCheckUtc\": \"2026-10-18T10:15:00Z\" }\n}"}],"_postman_id":"bdedda75-e5d4-c6b5-c223-210357d82b08"},{"name":"⚠⚠ M-PIN recovery – send a code (sends an OTP message)","id":"6536f71e-939a-6868-d6da-048958802ec8","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"channel\": \"{{recoveryChannel}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/unlock/recovery/code","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/unlock/recovery/code</code> · Bearer (collection auth) · <strong>HIGH IMPACT: the AI Zeny cloud sends a 6-digit code by email or WhatsApp to the organization administrator</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Never run without the owner's approval — a real message is sent.</strong> Normally the AI Zeny window does this (Welcome → <strong>Reset your M-PIN</strong>). Body <code>{ \"channel\": \"email\" | \"whatsapp\" }</code>. Answer <code>{ channel, destination (masked), codeExpiresUtc, resendAvailableUtc }</code>. The current M-PIN keeps working; nothing changes until a reset. <strong>Recovery:</strong> '⚠ M-PIN recovery – cancel'. LAN: <code>403 MPIN_RECOVERY_LOOPBACK_ONLY</code>. Never relayed. Run guard: <code>confirmHighImpact = POST /api/v1/unlock/recovery/code</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5ao; <code>docs/features/MPin-Recovery.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","unlock","recovery","code"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"b5c2b5e1-3e38-0a34-c575-bc47f5afa897","name":"200 – code sent to the masked contact (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"channel\": \"{{recoveryChannel}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/unlock/recovery/code","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/unlock/recovery/code` · Bearer (collection auth) · **HIGH IMPACT: the AI Zeny cloud sends a 6-digit code by email or WhatsApp to the organization administrator** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Never run without the owner's approval — a real message is sent.** Normally the AI Zeny window does this (Welcome → **Reset your M-PIN**). Body `{ \"channel\": \"email\" | \"whatsapp\" }`. Answer `{ channel, destination (masked), codeExpiresUtc, resendAvailableUtc }`. The current M-PIN keeps working; nothing changes until a reset. **Recovery:** '⚠ M-PIN recovery – cancel'. LAN: `403 MPIN_RECOVERY_LOOPBACK_ONLY`. Never relayed. Run guard: `confirmHighImpact = POST /api/v1/unlock/recovery/code`.\n\nContract: `docs/LOCAL-API.md` section 5ao; `docs/features/MPin-Recovery.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"61cf58192a3b4c5d6e7f8091a2b3c4e7","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"channel\": \"email\", \"destination\": \"o***r@e*****e.com\", \"codeExpiresUtc\": \"2026-10-18T06:25:00Z\", \"resendAvailableUtc\": \"2026-10-18T06:16:00Z\" },\n  \"metadata\": {}\n}"}],"_postman_id":"6536f71e-939a-6868-d6da-048958802ec8"},{"name":"⚠⚠ M-PIN recovery – verify the code","id":"943076fd-3212-2340-c199-8c50d0c66eef","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"channel\": \"{{recoveryChannel}}\",\n  \"code\": \"{{recoveryCode}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/unlock/recovery/verify","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/unlock/recovery/verify</code> · Bearer (collection auth) · <strong>HIGH IMPACT: part of replacing the PC's M-PIN</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Never run without the owner's approval.</strong> Body <code>{ channel, code }</code> (six ASCII digits from <code>{{recoveryCode}}</code>, secret, current value only). The cloud's reset authorization is held <strong>in the Host's memory only</strong> and never returned. Answer <code>{ verified: true, resetExpiresUtc }</code>. Wrong codes are counted by the cloud. LAN: <code>403 MPIN_RECOVERY_LOOPBACK_ONLY</code>. Run guard: <code>confirmHighImpact = POST /api/v1/unlock/recovery/verify</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5ao.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","unlock","recovery","verify"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"d9c44970-0023-557b-60e2-8657ea5b6621","name":"200 – code verified (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"channel\": \"{{recoveryChannel}}\",\n  \"code\": \"{{recoveryCode}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/unlock/recovery/verify","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/unlock/recovery/verify` · Bearer (collection auth) · **HIGH IMPACT: part of replacing the PC's M-PIN** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Never run without the owner's approval.** Body `{ channel, code }` (six ASCII digits from `{{recoveryCode}}`, secret, current value only). The cloud's reset authorization is held **in the Host's memory only** and never returned. Answer `{ verified: true, resetExpiresUtc }`. Wrong codes are counted by the cloud. LAN: `403 MPIN_RECOVERY_LOOPBACK_ONLY`. Run guard: `confirmHighImpact = POST /api/v1/unlock/recovery/verify`.\n\nContract: `docs/LOCAL-API.md` section 5ao."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Cache-Control","value":"no-store"},{"key":"X-Request-Id","value":"72d0692a3b4c5d6e7f8091a2b3c4d5f8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"verified\": true, \"resetExpiresUtc\": \"2026-10-18T06:30:00Z\" },\n  \"metadata\": {}\n}"}],"_postman_id":"943076fd-3212-2340-c199-8c50d0c66eef"},{"name":"⚠⚠ M-PIN recovery – reset (replaces the PC's M-PIN)","id":"ca7812b0-d2bc-c4c0-e883-e4e46ec6724e","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"value\": \"{{recoveryNewMpin}}\",\n  \"confirmation\": \"{{recoveryNewMpin}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/unlock/recovery/reset","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/unlock/recovery/reset</code> · Bearer (collection auth) · <strong>HIGHEST IMPACT: replaces the local unlock credential (M-PIN)</strong> (guarded by <code>confirmMutating</code> + <code>confirmHighImpact</code>)</p>\n<hr />\n<p><strong>Never run without the owner's explicit approval.</strong> Body <code>{ value, confirmation }</code> — the new 6-digit M-PIN (<code>{{recoveryNewMpin}}</code>, secret, current value only). The M-PIN rule is checked first; the cloud's <code>consume</code> is called <strong>once</strong> and never retried after a timeout; the new verifier is written, read back and the throttle cleared only after a checked 200. Any other outcome changes nothing. Enrollment, the device credential, tokens and the subscription are untouched. Answer: the <code>/unlock/create</code> answer (<code>credential</code>, <code>created: false</code>). <strong>Recovery:</strong> none other than another OTP recovery — the old M-PIN stops working. Run guard: <code>confirmHighImpact = POST /api/v1/unlock/recovery/reset</code>.</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5ao; <code>docs/features/MPin-Recovery.md</code>.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","unlock","recovery","reset"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"deba9a31-2810-7a70-090d-8f4ef3523421","name":"200 – M-PIN replaced (synthetic)","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"value\": \"{{recoveryNewMpin}}\",\n  \"confirmation\": \"{{recoveryNewMpin}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/unlock/recovery/reset","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/unlock/recovery/reset` · Bearer (collection auth) · **HIGHEST IMPACT: replaces the local unlock credential (M-PIN)** (guarded by `confirmMutating` + `confirmHighImpact`)\n\n---\n\n**Never run without the owner's explicit approval.** Body `{ value, confirmation }` — the new 6-digit M-PIN (`{{recoveryNewMpin}}`, secret, current value only). The M-PIN rule is checked first; the cloud's `consume` is called **once** and never retried after a timeout; the new verifier is written, read back and the throttle cleared only after a checked 200. Any other outcome changes nothing. Enrollment, the device credential, tokens and the subscription are untouched. Answer: the `/unlock/create` answer (`credential`, `created: false`). **Recovery:** none other than another OTP recovery — the old M-PIN stops working. Run guard: `confirmHighImpact = POST /api/v1/unlock/recovery/reset`.\n\nContract: `docs/LOCAL-API.md` section 5ao; `docs/features/MPin-Recovery.md`."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"83e17a3b4c5d6e7f8091a2b3c4d5e609","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"credential\": \"pin\", \"created\": false },\n  \"metadata\": {}\n}"}],"_postman_id":"ca7812b0-d2bc-c4c0-e883-e4e46ec6724e"},{"name":"⚠ M-PIN recovery – cancel","id":"6fe03c03-b0b9-3f48-4a2a-325d576c1d3d","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/unlock/recovery/cancel","description":"<p><strong>Local, this PC only</strong> · <code>POST {{baseUrl}}/api/v1/unlock/recovery/cancel</code> · Bearer (collection auth) · <strong>Changes AI Zeny on the PC</strong> (guarded by <code>confirmMutating</code>)</p>\n<hr />\n<p><strong>Mutating — run manually.</strong> Drops any recovery in progress (the in-memory reset authorization included). No body (ignored). Answer <code>{ cancelled: true }</code> — also when nothing was waiting (seen in the 2026-10-18 audit). The current M-PIN is unchanged. LAN: <code>403 MPIN_RECOVERY_LOOPBACK_ONLY</code> (seen in the audit).</p>\n<p>Contract: <code>docs/LOCAL-API.md</code> section 5ao.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","unlock","recovery","cancel"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"c67ba0a9-3b54-13f5-5a73-e27457cf4c5c","name":"200 – nothing waiting, still cancelled (as seen 2026-10-18)","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/unlock/recovery/cancel","description":"**Local, this PC only** · `POST {{baseUrl}}/api/v1/unlock/recovery/cancel` · Bearer (collection auth) · **Changes AI Zeny on the PC** (guarded by `confirmMutating`)\n\n---\n\n**Mutating — run manually.** Drops any recovery in progress (the in-memory reset authorization included). No body (ignored). Answer `{ cancelled: true }` — also when nothing was waiting (seen in the 2026-10-18 audit). The current M-PIN is unchanged. LAN: `403 MPIN_RECOVERY_LOOPBACK_ONLY` (seen in the audit).\n\nContract: `docs/LOCAL-API.md` section 5ao."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"no-store","key":"Cache-Control"},{"value":"94f28b4c5d6e7f8091a2b3c4d5e6f71a","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": { \"cancelled\": true },\n  \"metadata\": {}\n}"}],"_postman_id":"6fe03c03-b0b9-3f48-4a2a-325d576c1d3d"}],"id":"81a64c66-2c76-a1d0-a136-269ece720c11","_postman_id":"81a64c66-2c76-a1d0-a136-269ece720c11","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Write jobs & webhook status (Local only, read only)","item":[{"name":"GET write jobs (Local only)","id":"3487bee3-73b7-1b6f-cad0-879075c01815","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/write-jobs","description":"<p>Job summaries directly in data. Filters: companyCode, financialYear, operation, status, requestId, fromUtc inclusive, untilUtc exclusive, page default 1, pageSize default 50/max 100. No payload or webhook URL is returned.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","write-jobs"],"host":["{{baseUrl}}"],"query":[{"disabled":true,"description":{"content":"<p>Optional configured company code.</p>\n","type":"text/plain"},"key":"companyCode","value":"{{companyCode}}"},{"disabled":true,"description":{"content":"<p>Optional four-digit BUSY financial-year starting year.</p>\n","type":"text/plain"},"key":"financialYear","value":"{{financialYear}}"},{"disabled":true,"description":{"content":"<p>Optional exact operation name.</p>\n","type":"text/plain"},"key":"operation","value":"busy.sales-invoices.create"},{"disabled":true,"description":{"content":"<p>Optional: queued, running, recovering, succeeded, failed, manual_review.</p>\n","type":"text/plain"},"key":"status","value":"queued"},{"disabled":true,"description":{"content":"<p>Optional exact request ID.</p>\n","type":"text/plain"},"key":"requestId","value":"{{writeRequestId}}"},{"disabled":true,"description":{"content":"<p>Optional inclusive UTC creation timestamp.</p>\n","type":"text/plain"},"key":"fromUtc","value":"2026-10-20T00:00:00Z"},{"disabled":true,"description":{"content":"<p>Optional exclusive UTC creation timestamp.</p>\n","type":"text/plain"},"key":"untilUtc","value":"2026-10-21T00:00:00Z"},{"disabled":true,"description":{"content":"<p>Defaults to 1.</p>\n","type":"text/plain"},"key":"page","value":"1"},{"disabled":true,"description":{"content":"<p>Defaults to 50; maximum 100.</p>\n","type":"text/plain"},"key":"pageSize","value":"50"}],"variable":[]}},"response":[{"id":"d4051a70-7da2-286d-b133-5a7f21381877","name":"200 – write jobs page (synthetic)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{baseUrl}}/api/v1/write-jobs","host":["{{baseUrl}}"],"path":["api","v1","write-jobs"],"query":[{"description":"Optional configured company code.","value":"{{companyCode}}","key":"companyCode","disabled":true},{"description":"Optional four-digit BUSY financial-year starting year.","value":"{{financialYear}}","key":"financialYear","disabled":true},{"description":"Optional exact operation name.","value":"busy.sales-invoices.create","key":"operation","disabled":true},{"description":"Optional: queued, running, recovering, succeeded, failed, manual_review.","value":"queued","key":"status","disabled":true},{"description":"Optional exact request ID.","value":"{{writeRequestId}}","key":"requestId","disabled":true},{"description":"Optional inclusive UTC creation timestamp.","value":"2026-10-20T00:00:00Z","key":"fromUtc","disabled":true},{"description":"Optional exclusive UTC creation timestamp.","value":"2026-10-21T00:00:00Z","key":"untilUtc","disabled":true},{"description":"Defaults to 1.","value":"1","key":"page","disabled":true},{"description":"Defaults to 50; maximum 100.","value":"50","key":"pageSize","disabled":true}]},"description":"Job summaries directly in data. Filters: companyCode, financialYear, operation, status, requestId, fromUtc inclusive, untilUtc exclusive, page default 1, pageSize default 50/max 100. No payload or webhook URL is returned."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    {\n      \"jobId\": \"11111111111111111111111111111111\",\n      \"requestId\": \"synthetic-queue-001\",\n      \"companyCode\": \"COMP0002\",\n      \"financialYear\": \"2026\",\n      \"operation\": \"busy.sales-invoices.create\",\n      \"status\": \"queued\",\n      \"attempts\": 0,\n      \"createdUtc\": \"2026-10-20T10:00:00Z\",\n      \"updatedUtc\": \"2026-10-20T10:00:00Z\",\n      \"notificationStatus\": \"none\",\n      \"reason\": null\n    }\n  ],\n  \"metadata\": {\n    \"page\": 1,\n    \"pageSize\": 50,\n    \"returned\": 1\n  }\n}"}],"_postman_id":"3487bee3-73b7-1b6f-cad0-879075c01815"},{"name":"GET write job by ID (Local only)","id":"9fab4966-39ee-401d-9cc9-ff9029955d18","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/write-jobs/{{writeJobId}}","description":"<p>Use writeJobId from a 202 acknowledgement. data is {job,result}; result is null until a final business envelope is saved. Reconciled success may have a narrower savedRows shape. Invalid/unknown ID returns 404.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","write-jobs","{{writeJobId}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"00d2b57e-feda-aebf-6de2-f7f9a9793858","name":"200 – queued job detail (synthetic)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/write-jobs/{{writeJobId}}","description":"Use writeJobId from a 202 acknowledgement. data is {job,result}; result is null until a final business envelope is saved. Reconciled success may have a narrower savedRows shape. Invalid/unknown ID returns 404."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"job\": {\n      \"jobId\": \"11111111111111111111111111111111\",\n      \"requestId\": \"synthetic-queue-001\",\n      \"companyCode\": \"COMP0002\",\n      \"financialYear\": \"2026\",\n      \"operation\": \"busy.sales-invoices.create\",\n      \"status\": \"queued\",\n      \"attempts\": 0,\n      \"createdUtc\": \"2026-10-20T10:00:00Z\",\n      \"updatedUtc\": \"2026-10-20T10:00:00Z\",\n      \"notificationStatus\": \"none\",\n      \"reason\": null\n    },\n    \"result\": null\n  },\n  \"metadata\": {}\n}"},{"id":"732b0b34-4ed3-d99b-c24d-2abbc7d1e66b","name":"404 – unknown write job (synthetic)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/write-jobs/{{writeJobId}}","description":"Use writeJobId from a 202 acknowledgement. data is {job,result}; result is null until a final business envelope is saved. Reconciled success may have a narrower savedRows shape. Invalid/unknown ID returns 404."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"requestId\": \"synthetic-read-001\",\n    \"error\": {\n      \"code\": \"NOT_FOUND\",\n      \"message\": \"There is no such write job.\"\n    }\n  }\n}"}],"_postman_id":"9fab4966-39ee-401d-9cc9-ff9029955d18"},{"name":"GET company webhook status (Local only)","id":"e263a520-5b23-5bf4-bb81-b8cf39ca996b","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/companies/{{companyCode}}/write-webhook","description":"<p>Only {companyCode,configured} is returned; the stored URL is never read back. One webhook applies to all FYs of this company; no per-request destination.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","busy","companies","{{companyCode}}","write-webhook"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"936d5fa9-6f1a-1d2a-c1d9-6258a9b432dd","name":"200 – company webhook configured (URL never returned)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/busy/companies/{{companyCode}}/write-webhook","description":"Only {companyCode,configured} is returned; the stored URL is never read back. One webhook applies to all FYs of this company; no per-request destination."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"companyCode\": \"COMP0002\",\n    \"configured\": true\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"e263a520-5b23-5bf4-bb81-b8cf39ca996b"}],"id":"60a93a65-dc6b-7d36-389c-52eee56b9ac9","description":"<p>Local Bearer only. GET operations inspect durable write jobs or whether a company webhook exists. No request exposes a webhook URL. A 202 job acceptance is not a BUSY save.</p>\n","_postman_id":"60a93a65-dc6b-7d36-389c-52eee56b9ac9","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ Customer Integrations — write acceptance & run status (Local only)","item":[{"name":"⚠ Execute customer integration — one-send BUSY write","id":"6646d644-c72f-a90d-7e57-9031f12f9fe1","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"integrationName\": \"{{integrationName}}\",\n  \"runReference\": \"{{integrationRunReference}}\",\n  \"expectedRevision\": {{integrationExpectedRevision}},\n  \"payload\": {\"records\": [{\"id\": \"SYNTHETIC-001\"}]},\n  \"parameters\": {}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/execute-integration","description":"<p>Local source contract only. POST /api/v1/execute-integration. Required: companyCode, financialYear, integrationName (configured API name or stable ID), runReference (stable 1–200 chars). Optional: payload (JSON), parameters (object), expectedRevision (integer), additionalFinancialYear (string). Body max 1 MiB. Set nonempty fixture variables and confirmIntegrationRun=yes for exactly one send; guard consumes confirmation before send. Never automatically retry or use a new reference after 502/504/timeout/needs_review. HTTP 202 is durable parent acceptance, not native child-write completion. Poll integration-run-status and reconcile parent/child outcomes. A same-body/reference retry is only an explicit recovery step. Errors include 400 INTEGRATION_INVALID, 403 INTEGRATION_SCOPE_DENIED, 409 INTEGRATION_CHANGED/INTEGRATION_BUSY/INTEGRATION_CONTENT_CONFLICT/INTEGRATION_REVIEW_REQUIRED, and 504 INTEGRATION_ACCEPTANCE_UNCONFIRMED. Cloud route/deployment remains unverified. Synthetic examples are not live evidence.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","execute-integration"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"1cde93f5-81dc-af0b-c382-93c199f4dfb0","name":"SYNTHETIC 202 — parent accepted; child outcome pending","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"integrationName\": \"{{integrationName}}\",\n  \"runReference\": \"{{integrationRunReference}}\",\n  \"expectedRevision\": {{integrationExpectedRevision}},\n  \"payload\": {\"records\": [{\"id\": \"SYNTHETIC-001\"}]},\n  \"parameters\": {}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/execute-integration","description":"Local source contract only. POST /api/v1/execute-integration. Required: companyCode, financialYear, integrationName (configured API name or stable ID), runReference (stable 1–200 chars). Optional: payload (JSON), parameters (object), expectedRevision (integer), additionalFinancialYear (string). Body max 1 MiB. Set nonempty fixture variables and confirmIntegrationRun=yes for exactly one send; guard consumes confirmation before send. Never automatically retry or use a new reference after 502/504/timeout/needs_review. HTTP 202 is durable parent acceptance, not native child-write completion. Poll integration-run-status and reconcile parent/child outcomes. A same-body/reference retry is only an explicit recovery step. Errors include 400 INTEGRATION_INVALID, 403 INTEGRATION_SCOPE_DENIED, 409 INTEGRATION_CHANGED/INTEGRATION_BUSY/INTEGRATION_CONTENT_CONFLICT/INTEGRATION_REVIEW_REQUIRED, and 504 INTEGRATION_ACCEPTANCE_UNCONFIRMED. Cloud route/deployment remains unverified. Synthetic examples are not live evidence."},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": null,\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.integrations.execute\",\n    \"requestId\": \"req_synthetic_001\",\n    \"runId\": \"synthetic-run-001\",\n    \"integrationId\": \"synthetic-integration-001\",\n    \"revision\": 1,\n    \"status\": \"accepted\"\n  }\n}"},{"id":"abba4f8a-09b0-e71f-1d44-3eca8492c6ad","name":"SYNTHETIC 409 — changed revision (expected refusal)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"integrationName\": \"{{integrationName}}\",\n  \"runReference\": \"{{integrationRunReference}}\",\n  \"expectedRevision\": {{integrationExpectedRevision}},\n  \"payload\": {\"records\": [{\"id\": \"SYNTHETIC-001\"}]},\n  \"parameters\": {}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/execute-integration","description":"Local source contract only. POST /api/v1/execute-integration. Required: companyCode, financialYear, integrationName (configured API name or stable ID), runReference (stable 1–200 chars). Optional: payload (JSON), parameters (object), expectedRevision (integer), additionalFinancialYear (string). Body max 1 MiB. Set nonempty fixture variables and confirmIntegrationRun=yes for exactly one send; guard consumes confirmation before send. Never automatically retry or use a new reference after 502/504/timeout/needs_review. HTTP 202 is durable parent acceptance, not native child-write completion. Poll integration-run-status and reconcile parent/child outcomes. A same-body/reference retry is only an explicit recovery step. Errors include 400 INTEGRATION_INVALID, 403 INTEGRATION_SCOPE_DENIED, 409 INTEGRATION_CHANGED/INTEGRATION_BUSY/INTEGRATION_CONTENT_CONFLICT/INTEGRATION_REVIEW_REQUIRED, and 504 INTEGRATION_ACCEPTANCE_UNCONFIRMED. Cloud route/deployment remains unverified. Synthetic examples are not live evidence."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INTEGRATION_CHANGED\",\n      \"message\": \"The integration revision changed.\"\n    },\n    \"requestId\": \"req_synthetic_refusal_001\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"75a16ac2-1aa5-81ce-7fa6-bd353ad97c95","name":"SYNTHETIC 504 — acceptance unconfirmed; retain reference","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"integrationName\": \"{{integrationName}}\",\n  \"runReference\": \"{{integrationRunReference}}\",\n  \"expectedRevision\": {{integrationExpectedRevision}},\n  \"payload\": {\"records\": [{\"id\": \"SYNTHETIC-001\"}]},\n  \"parameters\": {}\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/execute-integration","description":"Local source contract only. POST /api/v1/execute-integration. Required: companyCode, financialYear, integrationName (configured API name or stable ID), runReference (stable 1–200 chars). Optional: payload (JSON), parameters (object), expectedRevision (integer), additionalFinancialYear (string). Body max 1 MiB. Set nonempty fixture variables and confirmIntegrationRun=yes for exactly one send; guard consumes confirmation before send. Never automatically retry or use a new reference after 502/504/timeout/needs_review. HTTP 202 is durable parent acceptance, not native child-write completion. Poll integration-run-status and reconcile parent/child outcomes. A same-body/reference retry is only an explicit recovery step. Errors include 400 INTEGRATION_INVALID, 403 INTEGRATION_SCOPE_DENIED, 409 INTEGRATION_CHANGED/INTEGRATION_BUSY/INTEGRATION_CONTENT_CONFLICT/INTEGRATION_REVIEW_REQUIRED, and 504 INTEGRATION_ACCEPTANCE_UNCONFIRMED. Cloud route/deployment remains unverified. Synthetic examples are not live evidence."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INTEGRATION_ACCEPTANCE_UNCONFIRMED\",\n      \"message\": \"Durable acceptance could not be confirmed. Inspect the run or submit the identical input with the same runReference; never invent a replacement reference.\"\n    },\n    \"requestId\": \"req_synthetic_refusal_001\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"6646d644-c72f-a90d-7e57-9031f12f9fe1"},{"name":"Integration run status — inspect accepted parent and children","id":"eb645b53-13cf-c75f-dd10-2016308435f9","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"runId\": \"{{integrationRunId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/integration-run-status","description":"<p>Local source contract only. POST /api/v1/integration-run-status (read only). Requires companyCode, financialYear and a known runId from a durable 202 receipt or investigation. Optional additionalFinancialYear. HTTP 200 returns {success:true,data:{run,items,output,failure},metadata:{apiVersion,operation,requestId}}. Run status may be accepted/running/awaiting_writes/succeeded/failed/partial/interrupted/stopping/cancelled/needs_review. Inspect each child result; 200 alone does not mean a native write succeeded. Expected refusals include 400 INTEGRATION_INVALID, 403 INTEGRATION_SCOPE_DENIED and 404 INTEGRATION_NOT_FOUND. Cloud deployment remains unverified. Examples are synthetic.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","integration-run-status"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"83194bb5-a4b6-205c-438d-97e51ff2457d","name":"SYNTHETIC 200 — awaiting child writes","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"runId\": \"{{integrationRunId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/integration-run-status","description":"Local source contract only. POST /api/v1/integration-run-status (read only). Requires companyCode, financialYear and a known runId from a durable 202 receipt or investigation. Optional additionalFinancialYear. HTTP 200 returns {success:true,data:{run,items,output,failure},metadata:{apiVersion,operation,requestId}}. Run status may be accepted/running/awaiting_writes/succeeded/failed/partial/interrupted/stopping/cancelled/needs_review. Inspect each child result; 200 alone does not mean a native write succeeded. Expected refusals include 400 INTEGRATION_INVALID, 403 INTEGRATION_SCOPE_DENIED and 404 INTEGRATION_NOT_FOUND. Cloud deployment remains unverified. Examples are synthetic."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"run\": {\n      \"id\": \"synthetic-run-001\",\n      \"integrationId\": \"synthetic-integration-001\",\n      \"companyCode\": \"COMP0001\",\n      \"financialYear\": \"2026\",\n      \"reference\": \"SYNTHETIC-REFERENCE-001\",\n      \"revision\": 1,\n      \"status\": \"awaiting_writes\",\n      \"active\": true,\n      \"createdUtc\": \"2026-10-22T12:00:00+00:00\",\n      \"updatedUtc\": \"2026-10-22T12:00:01+00:00\",\n      \"stateVersion\": 1,\n      \"origin\": \"local\"\n    },\n    \"items\": [\n      {\n        \"intentId\": \"synthetic-intent-001\",\n        \"generation\": 1,\n        \"operation\": \"busy.sales-orders.create\",\n        \"key\": \"SYNTHETIC-KEY-001\",\n        \"contentHash\": \"synthetic-content-hash\",\n        \"result\": {\n          \"state\": \"queued\",\n          \"jobId\": \"synthetic-job-001\",\n          \"data\": null,\n          \"metadata\": null,\n          \"error\": null\n        },\n        \"noWriteProven\": false\n      }\n    ],\n    \"output\": null,\n    \"failure\": null\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.integration-runs.get\",\n    \"requestId\": \"req_synthetic_status_001\"\n  }\n}"},{"id":"907fcba5-f020-810b-b3e6-5ab15db79c93","name":"SYNTHETIC 200 — verified parent success","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"runId\": \"{{integrationRunId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/integration-run-status","description":"Local source contract only. POST /api/v1/integration-run-status (read only). Requires companyCode, financialYear and a known runId from a durable 202 receipt or investigation. Optional additionalFinancialYear. HTTP 200 returns {success:true,data:{run,items,output,failure},metadata:{apiVersion,operation,requestId}}. Run status may be accepted/running/awaiting_writes/succeeded/failed/partial/interrupted/stopping/cancelled/needs_review. Inspect each child result; 200 alone does not mean a native write succeeded. Expected refusals include 400 INTEGRATION_INVALID, 403 INTEGRATION_SCOPE_DENIED and 404 INTEGRATION_NOT_FOUND. Cloud deployment remains unverified. Examples are synthetic."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"run\": {\n      \"id\": \"synthetic-run-001\",\n      \"integrationId\": \"synthetic-integration-001\",\n      \"companyCode\": \"COMP0001\",\n      \"financialYear\": \"2026\",\n      \"reference\": \"SYNTHETIC-REFERENCE-001\",\n      \"revision\": 1,\n      \"status\": \"succeeded\",\n      \"active\": false,\n      \"createdUtc\": \"2026-10-22T12:00:00+00:00\",\n      \"updatedUtc\": \"2026-10-22T12:00:01+00:00\",\n      \"stateVersion\": 1,\n      \"origin\": \"local\"\n    },\n    \"items\": [\n      {\n        \"intentId\": \"synthetic-intent-001\",\n        \"generation\": 1,\n        \"operation\": \"busy.sales-orders.create\",\n        \"key\": \"SYNTHETIC-KEY-001\",\n        \"contentHash\": \"synthetic-content-hash\",\n        \"result\": {\n          \"state\": \"succeeded\",\n          \"jobId\": \"synthetic-job-001\",\n          \"data\": null,\n          \"metadata\": null,\n          \"error\": null\n        },\n        \"noWriteProven\": false\n      }\n    ],\n    \"output\": {\n      \"processed\": 1\n    },\n    \"failure\": null\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.integration-runs.get\",\n    \"requestId\": \"req_synthetic_status_001\"\n  }\n}"},{"id":"78c38edc-0c49-4ac9-5938-3190cdfabf1e","name":"SYNTHETIC 200 — partial child outcome","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"runId\": \"{{integrationRunId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/integration-run-status","description":"Local source contract only. POST /api/v1/integration-run-status (read only). Requires companyCode, financialYear and a known runId from a durable 202 receipt or investigation. Optional additionalFinancialYear. HTTP 200 returns {success:true,data:{run,items,output,failure},metadata:{apiVersion,operation,requestId}}. Run status may be accepted/running/awaiting_writes/succeeded/failed/partial/interrupted/stopping/cancelled/needs_review. Inspect each child result; 200 alone does not mean a native write succeeded. Expected refusals include 400 INTEGRATION_INVALID, 403 INTEGRATION_SCOPE_DENIED and 404 INTEGRATION_NOT_FOUND. Cloud deployment remains unverified. Examples are synthetic."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"run\": {\n      \"id\": \"synthetic-run-001\",\n      \"integrationId\": \"synthetic-integration-001\",\n      \"companyCode\": \"COMP0001\",\n      \"financialYear\": \"2026\",\n      \"reference\": \"SYNTHETIC-REFERENCE-001\",\n      \"revision\": 1,\n      \"status\": \"partial\",\n      \"active\": true,\n      \"createdUtc\": \"2026-10-22T12:00:00+00:00\",\n      \"updatedUtc\": \"2026-10-22T12:00:01+00:00\",\n      \"stateVersion\": 1,\n      \"origin\": \"local\"\n    },\n    \"items\": [\n      {\n        \"intentId\": \"synthetic-intent-001\",\n        \"generation\": 1,\n        \"operation\": \"busy.sales-orders.create\",\n        \"key\": \"SYNTHETIC-KEY-001\",\n        \"contentHash\": \"synthetic-content-hash\",\n        \"result\": {\n          \"state\": \"succeeded\",\n          \"jobId\": \"synthetic-job-001\",\n          \"data\": null,\n          \"metadata\": null,\n          \"error\": null\n        },\n        \"noWriteProven\": false\n      },\n      {\n        \"intentId\": \"synthetic-intent-002\",\n        \"generation\": 1,\n        \"operation\": \"busy.sales-orders.create\",\n        \"key\": \"SYNTHETIC-KEY-002\",\n        \"contentHash\": \"synthetic-content-hash\",\n        \"result\": {\n          \"state\": \"failed\",\n          \"jobId\": \"synthetic-job-002\",\n          \"data\": null,\n          \"metadata\": null,\n          \"error\": {\n            \"code\": \"SYNTHETIC_CHILD_REFUSAL\",\n            \"message\": \"Synthetic child refused.\",\n            \"field\": null,\n            \"details\": null,\n            \"status\": 422\n          }\n        },\n        \"noWriteProven\": false\n      }\n    ],\n    \"output\": null,\n    \"failure\": null\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.integration-runs.get\",\n    \"requestId\": \"req_synthetic_status_001\"\n  }\n}"},{"id":"175a611f-5c71-6d8e-cb62-796578a7aa48","name":"SYNTHETIC 200 — needs review; never resend blindly","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"runId\": \"{{integrationRunId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/integration-run-status","description":"Local source contract only. POST /api/v1/integration-run-status (read only). Requires companyCode, financialYear and a known runId from a durable 202 receipt or investigation. Optional additionalFinancialYear. HTTP 200 returns {success:true,data:{run,items,output,failure},metadata:{apiVersion,operation,requestId}}. Run status may be accepted/running/awaiting_writes/succeeded/failed/partial/interrupted/stopping/cancelled/needs_review. Inspect each child result; 200 alone does not mean a native write succeeded. Expected refusals include 400 INTEGRATION_INVALID, 403 INTEGRATION_SCOPE_DENIED and 404 INTEGRATION_NOT_FOUND. Cloud deployment remains unverified. Examples are synthetic."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"run\": {\n      \"id\": \"synthetic-run-001\",\n      \"integrationId\": \"synthetic-integration-001\",\n      \"companyCode\": \"COMP0001\",\n      \"financialYear\": \"2026\",\n      \"reference\": \"SYNTHETIC-REFERENCE-001\",\n      \"revision\": 1,\n      \"status\": \"needs_review\",\n      \"active\": true,\n      \"createdUtc\": \"2026-10-22T12:00:00+00:00\",\n      \"updatedUtc\": \"2026-10-22T12:00:01+00:00\",\n      \"stateVersion\": 1,\n      \"origin\": \"local\"\n    },\n    \"items\": [\n      {\n        \"intentId\": \"synthetic-intent-001\",\n        \"generation\": 1,\n        \"operation\": \"busy.sales-orders.create\",\n        \"key\": \"SYNTHETIC-KEY-001\",\n        \"contentHash\": \"synthetic-content-hash\",\n        \"result\": {\n          \"state\": \"needs_review\",\n          \"jobId\": \"synthetic-job-001\",\n          \"data\": null,\n          \"metadata\": null,\n          \"error\": null\n        },\n        \"noWriteProven\": false\n      }\n    ],\n    \"output\": null,\n    \"failure\": null\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.integration-runs.get\",\n    \"requestId\": \"req_synthetic_status_001\"\n  }\n}"},{"id":"95227ee1-9b86-bf62-6ac4-ddd37672de6a","name":"SYNTHETIC 404 — run not found (expected refusal)","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"runId\": \"{{integrationRunId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{baseUrl}}/api/v1/integration-run-status","description":"Local source contract only. POST /api/v1/integration-run-status (read only). Requires companyCode, financialYear and a known runId from a durable 202 receipt or investigation. Optional additionalFinancialYear. HTTP 200 returns {success:true,data:{run,items,output,failure},metadata:{apiVersion,operation,requestId}}. Run status may be accepted/running/awaiting_writes/succeeded/failed/partial/interrupted/stopping/cancelled/needs_review. Inspect each child result; 200 alone does not mean a native write succeeded. Expected refusals include 400 INTEGRATION_INVALID, 403 INTEGRATION_SCOPE_DENIED and 404 INTEGRATION_NOT_FOUND. Cloud deployment remains unverified. Examples are synthetic."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INTEGRATION_NOT_FOUND\",\n      \"message\": \"The integration run was not found.\"\n    },\n    \"requestId\": \"req_synthetic_refusal_001\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"eb645b53-13cf-c75f-dd10-2016308435f9"}],"id":"8c11b715-e0f5-12d7-2017-8ccffbc4b66d","_postman_id":"8c11b715-e0f5-12d7-2017-8ccffbc4b66d","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ WhatsApp backend — Local only (opt-in; no Relay)","item":[{"name":"WhatsApp status — read-only, default-off and workers","id":"39cdbdf6-ea73-9a84-da31-72a0510c1515","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/whatsapp/status","description":"<p>LOCAL only. Authenticated status is safe to read from this PC or a permitted LAN client. Master and every profile default off. Profiles, workers and profileStates expose state/resources and saved-state existence metadata, not QR, keys or message bodies. Each profileStates entry has profileId, generation and hasSavedState; saved state alone does not prove a linked account. HTTP 200 describes current state; it is not pairing, sending or delivery proof. For a deliberate refusal test set waExpectedStatus AND waExpectedCode to the exact documented pair, then clear both; a generic error never passes the ordinary success case. Synthetic examples are not live evidence.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","whatsapp","status"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"5ce97bfe-2aa2-0b7e-edb9-02cdc88164fc","name":"SYNTHETIC 200 — default off, zero workers","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/whatsapp/status","description":"LOCAL only. Authenticated status is safe to read from this PC or a permitted LAN client. Master and every profile default off. Profiles, workers and profileStates expose state/resources and saved-state existence metadata, not QR, keys or message bodies. Each profileStates entry has profileId, generation and hasSavedState; saved state alone does not prove a linked account. HTTP 200 describes current state; it is not pairing, sending or delivery proof. For a deliberate refusal test set waExpectedStatus AND waExpectedCode to the exact documented pair, then clear both; a generic error never passes the ordinary success case. Synthetic examples are not live evidence."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"enabled\": false,\n    \"activationAllowed\": true,\n    \"profiles\": [],\n    \"workers\": [],\n    \"degraded\": false,\n    \"profileStates\": []\n  },\n  \"metadata\": {}\n}"},{"id":"7987b7ac-4ea2-b4f8-75de-6c174d27bd99","name":"SYNTHETIC 503 — backend unavailable","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/whatsapp/status","description":"LOCAL only. Authenticated status is safe to read from this PC or a permitted LAN client. Master and every profile default off. Profiles, workers and profileStates expose state/resources and saved-state existence metadata, not QR, keys or message bodies. Each profileStates entry has profileId, generation and hasSavedState; saved state alone does not prove a linked account. HTTP 200 describes current state; it is not pairing, sending or delivery proof. For a deliberate refusal test set waExpectedStatus AND waExpectedCode to the exact documented pair, then clear both; a generic error never passes the ordinary success case. Synthetic examples are not live evidence."},"status":"Service Unavailable","code":503,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"WHATSAPP_UNAVAILABLE\",\"message\":\"Synthetic refusal; inspect the actual response before retrying.\"}}}"}],"_postman_id":"39cdbdf6-ea73-9a84-da31-72a0510c1515"},{"name":"⚠ Create WhatsApp profile — one-send Local control","id":"4e22ec16-4c11-0a42-5a92-07c1e64eb7c5","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\"displayName\":\"{{waDisplayName}}\"}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles","description":"<p>Local loopback only. Creates a disabled named profile; does not pair or send. displayName is required, nonblank, max 100 chars. All saved WhatsApp profiles (including disabled and logged-out) count against the current subscription companyCount used for BUSY company connections. 409 WHATSAPP_PLAN_UNKNOWN refuses creation when that allowance cannot be confirmed. 409 WHATSAPP_PROFILE_LIMIT refuses creation when full and returns metadata.error.details.companyLimit and profileCount. Reducing an allowance retains existing profiles but blocks new ones; disabling/logging out does not release a slot. Set waDisplayName and confirmWhatsAppControl=yes for one authorized action. No real profile names in examples. Keep master off until separately approved live pairing. 200 returns the new profile. For an exact expected refusal, set waExpectedStatus=409 and waExpectedCode to WHATSAPP_PROFILE_LIMIT or WHATSAPP_PLAN_UNKNOWN; set both together and clear afterwards. Do not resend after an uncertain result.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","whatsapp","profiles"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"4152d187-0842-b2ca-6cdb-97c4aad215b6","name":"SYNTHETIC 200 — disabled profile created","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\"displayName\":\"{{waDisplayName}}\"}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles","description":"Local loopback only. Creates a disabled named profile; does not pair or send. displayName is required, nonblank, max 100 chars. All saved WhatsApp profiles (including disabled and logged-out) count against the current subscription companyCount used for BUSY company connections. 409 WHATSAPP_PLAN_UNKNOWN refuses creation when that allowance cannot be confirmed. 409 WHATSAPP_PROFILE_LIMIT refuses creation when full and returns metadata.error.details.companyLimit and profileCount. Reducing an allowance retains existing profiles but blocks new ones; disabling/logging out does not release a slot. Set waDisplayName and confirmWhatsAppControl=yes for one authorized action. No real profile names in examples. Keep master off until separately approved live pairing. 200 returns the new profile. For an exact expected refusal, set waExpectedStatus=409 and waExpectedCode to WHATSAPP_PROFILE_LIMIT or WHATSAPP_PLAN_UNKNOWN; set both together and clear afterwards. Do not resend after an uncertain result."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"profileId\": \"11111111-1111-4111-8111-111111111111\",\n    \"displayName\": \"Synthetic test profile\",\n    \"enabled\": false,\n    \"generation\": 1,\n    \"revision\": 0\n  },\n  \"metadata\": {}\n}"},{"id":"b989bf12-92df-d2f0-1fb0-2db258de93d8","name":"SYNTHETIC 409 — profile allowance full","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\"displayName\":\"{{waDisplayName}}\"}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles","description":"Local loopback only. Creates a disabled named profile; does not pair or send. displayName is required, nonblank, max 100 chars. All saved WhatsApp profiles (including disabled and logged-out) count against the current subscription companyCount used for BUSY company connections. 409 WHATSAPP_PLAN_UNKNOWN refuses creation when that allowance cannot be confirmed. 409 WHATSAPP_PROFILE_LIMIT refuses creation when full and returns metadata.error.details.companyLimit and profileCount. Reducing an allowance retains existing profiles but blocks new ones; disabling/logging out does not release a slot. Set waDisplayName and confirmWhatsAppControl=yes for one authorized action. No real profile names in examples. Keep master off until separately approved live pairing. 200 returns the new profile. For an exact expected refusal, set waExpectedStatus=409 and waExpectedCode to WHATSAPP_PROFILE_LIMIT or WHATSAPP_PLAN_UNKNOWN; set both together and clear afterwards. Do not resend after an uncertain result."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"WHATSAPP_PROFILE_LIMIT\",\n      \"message\": \"Your company allowance is already occupied by WhatsApp profiles. Contact support to increase the allowance.\",\n      \"details\": {\n        \"companyLimit\": 1,\n        \"profileCount\": 1\n      }\n    }\n  }\n}"},{"id":"7249d04a-210d-57cc-2d33-13abe60aa473","name":"SYNTHETIC 409 — company allowance unknown","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\"displayName\":\"{{waDisplayName}}\"}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles","description":"Local loopback only. Creates a disabled named profile; does not pair or send. displayName is required, nonblank, max 100 chars. All saved WhatsApp profiles (including disabled and logged-out) count against the current subscription companyCount used for BUSY company connections. 409 WHATSAPP_PLAN_UNKNOWN refuses creation when that allowance cannot be confirmed. 409 WHATSAPP_PROFILE_LIMIT refuses creation when full and returns metadata.error.details.companyLimit and profileCount. Reducing an allowance retains existing profiles but blocks new ones; disabling/logging out does not release a slot. Set waDisplayName and confirmWhatsAppControl=yes for one authorized action. No real profile names in examples. Keep master off until separately approved live pairing. 200 returns the new profile. For an exact expected refusal, set waExpectedStatus=409 and waExpectedCode to WHATSAPP_PROFILE_LIMIT or WHATSAPP_PLAN_UNKNOWN; set both together and clear afterwards. Do not resend after an uncertain result."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"WHATSAPP_PLAN_UNKNOWN\",\n      \"message\": \"AI Zeny could not confirm your company allowance. Connect to the internet and refresh the subscription.\"\n    }\n  }\n}"}],"_postman_id":"4e22ec16-4c11-0a42-5a92-07c1e64eb7c5"},{"name":"⚠ Set WhatsApp master switch — one-send Local control","id":"62ed97ae-d363-3b4c-3ebb-f5a0ba28cc36","request":{"method":"PUT","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"enabled\":{{waMasterEnabled}}}"},"url":"{{baseUrl}}/api/v1/whatsapp/enabled","description":"<p>Local loopback only. Persistent master opt-in switch; false is the safe default and stops all WhatsApp children. enabled must be JSON boolean. Turning true may start enabled profiles; requires separate approved real-account acceptance. One-send confirmWhatsAppControl=yes is consumed before request.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","whatsapp","enabled"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"7f65b470-cfa8-0471-a23b-4f08b202f5ae","name":"SYNTHETIC 200 — master remains off","originalRequest":{"method":"PUT","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"enabled\":{{waMasterEnabled}}}"},"url":"{{baseUrl}}/api/v1/whatsapp/enabled","description":"Local loopback only. Persistent master opt-in switch; false is the safe default and stops all WhatsApp children. enabled must be JSON boolean. Turning true may start enabled profiles; requires separate approved real-account acceptance. One-send confirmWhatsAppControl=yes is consumed before request."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"enabled\": false,\n    \"activationAllowed\": true,\n    \"profiles\": [\n      {\n        \"profileId\": \"11111111-1111-4111-8111-111111111111\",\n        \"displayName\": \"Synthetic test profile\",\n        \"enabled\": false,\n        \"generation\": 1,\n        \"revision\": 0\n      }\n    ],\n    \"workers\": [],\n    \"degraded\": false\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"62ed97ae-d363-3b4c-3ebb-f5a0ba28cc36"},{"name":"⚠ Set WhatsApp profile switch — one-send Local control","id":"31f693cd-c626-70ed-5c8e-0383e4b43015","request":{"method":"PUT","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"enabled\":{{waProfileEnabled}}}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/enabled","description":"<p>Local loopback only. Persistent per-profile opt-in; off stops only selected profile and retains pairing. Turning on may start a private worker when master is on. Use a real waProfileId fixture and one-send confirmWhatsAppControl=yes. Success returns full status; inspect the selected profile, not just HTTP 200.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","whatsapp","profiles","{{waProfileId}}","enabled"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"c6105444-1a32-f89f-4952-5d0cc27ff897","name":"SYNTHETIC 200 — profile remains off","originalRequest":{"method":"PUT","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"enabled\":{{waProfileEnabled}}}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/enabled","description":"Local loopback only. Persistent per-profile opt-in; off stops only selected profile and retains pairing. Turning on may start a private worker when master is on. Use a real waProfileId fixture and one-send confirmWhatsAppControl=yes. Success returns full status; inspect the selected profile, not just HTTP 200."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"enabled\": false,\n    \"activationAllowed\": true,\n    \"profiles\": [\n      {\n        \"profileId\": \"11111111-1111-4111-8111-111111111111\",\n        \"displayName\": \"Synthetic test profile\",\n        \"enabled\": false,\n        \"generation\": 1,\n        \"revision\": 0\n      }\n    ],\n    \"workers\": [],\n    \"degraded\": false\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"31f693cd-c626-70ed-5c8e-0383e4b43015"},{"name":"⚠ Pair WhatsApp profile — one-send Local control","id":"baddab3c-49dc-0f1f-4f61-ee1733fdd6bb","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/pair","description":"<p>Local loopback only. Starts pairing on an enabled unpaired profile. Requires explicit owner-approved account and live pairing; do not run while merely editing collection. Pair response means accepted, not registered/connected. Never save real QR, session or key material. One-send guard confirmWhatsAppControl=yes.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","whatsapp","profiles","{{waProfileId}}","pair"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"f237bf65-66f1-3dd3-0a73-1a17eb5642ff","name":"SYNTHETIC 200 — pairing accepted","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/pair","description":"Local loopback only. Starts pairing on an enabled unpaired profile. Requires explicit owner-approved account and live pairing; do not run while merely editing collection. Pair response means accepted, not registered/connected. Never save real QR, session or key material. One-send guard confirmWhatsAppControl=yes."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"accepted\": true\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"baddab3c-49dc-0f1f-4f61-ee1733fdd6bb"},{"name":"⚠ Read WhatsApp QR — sensitive Local control","id":"c1ce0a03-6ebb-a935-bcee-312a211d5317","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/qr","description":"<p>Local loopback only. Sensitive ephemeral pairing QR, no-store response. Result contains qr (string or null), current account generation and expiresAtUtc (actual worker expiry, null when qr is null). A read does not extend expiry or start pairing. Requires separate owner-approved pairing and one-send confirmWhatsAppQrRead=yes. Do not save/copy a real QR or make its response an example. Synthetic example uses null only.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","whatsapp","profiles","{{waProfileId}}","qr"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"e4ed7689-d352-faba-2d6b-44b9933ac3d3","name":"SYNTHETIC 200 — no QR yet","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/qr","description":"Local loopback only. Sensitive ephemeral pairing QR, no-store response. Result contains qr (string or null), current account generation and expiresAtUtc (actual worker expiry, null when qr is null). A read does not extend expiry or start pairing. Requires separate owner-approved pairing and one-send confirmWhatsAppQrRead=yes. Do not save/copy a real QR or make its response an example. Synthetic example uses null only."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"qr\": null,\n    \"generation\": 1,\n    \"expiresAtUtc\": null\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"c1ce0a03-6ebb-a935-bcee-312a211d5317"},{"name":"⚠ Logout WhatsApp profile — one-send Local control","id":"6abc2a5e-004e-eeeb-36c8-7bc3be05445c","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/logout","description":"<p>Local loopback only. Logout disables profile and advances generation; old generation requests refuse. This changes account state; never run casually. Requires one-send confirmWhatsAppControl=yes and approved live profile. 200 loggedOut=true is control completion, not delivery proof.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","whatsapp","profiles","{{waProfileId}}","logout"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"47499291-45bf-703b-c5ec-a46e1cc07f52","name":"SYNTHETIC 200 — logged out","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/logout","description":"Local loopback only. Logout disables profile and advances generation; old generation requests refuse. This changes account state; never run casually. Requires one-send confirmWhatsAppControl=yes and approved live profile. 200 loggedOut=true is control completion, not delivery proof."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"loggedOut\": true\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"6abc2a5e-004e-eeeb-36c8-7bc3be05445c"},{"name":"⚠ Stop WhatsApp profile — one-send Local control","id":"343fadec-709f-3cfa-5a09-90adb0d31ba5","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/stop","description":"<p>Local loopback only. Persists profile off and drains its owned worker while retaining pairing; no new send intent. Requires one-send confirmWhatsAppControl=yes. Do not confuse stop with logout; uncertain sends remain unretried.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","whatsapp","profiles","{{waProfileId}}","stop"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"41339e48-b845-945e-54d8-4e27cd3104d2","name":"SYNTHETIC 200 — profile stopped","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/stop","description":"Local loopback only. Persists profile off and drains its owned worker while retaining pairing; no new send intent. Requires one-send confirmWhatsAppControl=yes. Do not confuse stop with logout; uncertain sends remain unretried."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"stopped\": true\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"343fadec-709f-3cfa-5a09-90adb0d31ba5"},{"name":"⚠ Restart WhatsApp profile — one-send Local control","id":"d3944128-b01b-cc1a-dfb3-8409bd1ff392","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/restart","description":"<p>Local loopback only. Restart only an enabled profile; may start private worker. Requires one-send confirmWhatsAppControl=yes and an approved profile. 200 accepted=true is not proof of registration or message delivery.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","whatsapp","profiles","{{waProfileId}}","restart"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"3ec10420-fbd9-3c3f-705e-3b33ca643177","name":"SYNTHETIC 200 — restart accepted","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/restart","description":"Local loopback only. Restart only an enabled profile; may start private worker. Requires one-send confirmWhatsAppControl=yes and an approved profile. 200 accepted=true is not proof of registration or message delivery."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"accepted\": true\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"d3944128-b01b-cc1a-dfb3-8409bd1ff392"},{"name":"⚠ Send WhatsApp direct text — durable 202, one-send","id":"57548c8b-8356-7ec7-3240-ca26266678b3","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\"generation\":{{waGeneration}},\"idempotencyKey\":\"{{waIdempotencyKey}}\",\"recipient\":\"{{waRecipient}}\",\"text\":\"{{waText}}\"}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/messages","description":"<p>Local PC/permitted LAN. Only with separately approved sender profile and recipient. Required: generation from current status, idempotencyKey (1–128 chars), recipient 7–15 international digits, nonblank direct text &lt;=16,384 UTF-8 bytes. One voucher-level sender profile; no inferred account. Set all wa* fixtures and confirmWhatsAppSend=yes for exactly one authorized send; guard consumes it. HTTP 202 means durable acceptance only, not socket write, server ACK, delivery or read. Poll operation/events. Lost/uncertain result: inspect same operation/key; NEVER automatically resend or invent a new key. Groups, arbitrary media formats and history are not silently sent; image/PDF/video uses the separate guarded Local media route after installation.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","whatsapp","profiles","{{waProfileId}}","messages"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"43a4a4d8-223c-121a-d5f2-f570015c8664","name":"SYNTHETIC 202 — durable acceptance only","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\"generation\":{{waGeneration}},\"idempotencyKey\":\"{{waIdempotencyKey}}\",\"recipient\":\"{{waRecipient}}\",\"text\":\"{{waText}}\"}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/messages","description":"Local PC/permitted LAN. Only with separately approved sender profile and recipient. Required: generation from current status, idempotencyKey (1–128 chars), recipient 7–15 international digits, nonblank direct text <=16,384 UTF-8 bytes. One voucher-level sender profile; no inferred account. Set all wa* fixtures and confirmWhatsAppSend=yes for exactly one authorized send; guard consumes it. HTTP 202 means durable acceptance only, not socket write, server ACK, delivery or read. Poll operation/events. Lost/uncertain result: inspect same operation/key; NEVER automatically resend or invent a new key. Groups, arbitrary media formats and history are not silently sent; image/PDF/video uses the separate guarded Local media route after installation."},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"operationId\": \"22222222-2222-4222-8222-222222222222\",\n    \"profileId\": \"11111111-1111-4111-8111-111111111111\",\n    \"generation\": 1,\n    \"phase\": \"accepted\"\n  },\n  \"metadata\": {}\n}"},{"id":"d93eadcd-b847-5f1b-2661-f108fe8f4e54","name":"SYNTHETIC 403 — activation required","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\"generation\":{{waGeneration}},\"idempotencyKey\":\"{{waIdempotencyKey}}\",\"recipient\":\"{{waRecipient}}\",\"text\":\"{{waText}}\"}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/messages","description":"Local PC/permitted LAN. Only with separately approved sender profile and recipient. Required: generation from current status, idempotencyKey (1–128 chars), recipient 7–15 international digits, nonblank direct text <=16,384 UTF-8 bytes. One voucher-level sender profile; no inferred account. Set all wa* fixtures and confirmWhatsAppSend=yes for exactly one authorized send; guard consumes it. HTTP 202 means durable acceptance only, not socket write, server ACK, delivery or read. Poll operation/events. Lost/uncertain result: inspect same operation/key; NEVER automatically resend or invent a new key. Groups, arbitrary media formats and history are not silently sent; image/PDF/video uses the separate guarded Local media route after installation."},"status":"Forbidden","code":403,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"WHATSAPP_ACTIVATION_REQUIRED\",\"message\":\"Synthetic refusal; inspect the actual response before retrying.\"}}}"},{"id":"7fc209c6-498d-71f9-1e06-410ee518dc9a","name":"SYNTHETIC 409 — generation conflict, do not auto-retry","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\"generation\":{{waGeneration}},\"idempotencyKey\":\"{{waIdempotencyKey}}\",\"recipient\":\"{{waRecipient}}\",\"text\":\"{{waText}}\"}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/messages","description":"Local PC/permitted LAN. Only with separately approved sender profile and recipient. Required: generation from current status, idempotencyKey (1–128 chars), recipient 7–15 international digits, nonblank direct text <=16,384 UTF-8 bytes. One voucher-level sender profile; no inferred account. Set all wa* fixtures and confirmWhatsAppSend=yes for exactly one authorized send; guard consumes it. HTTP 202 means durable acceptance only, not socket write, server ACK, delivery or read. Poll operation/events. Lost/uncertain result: inspect same operation/key; NEVER automatically resend or invent a new key. Groups, arbitrary media formats and history are not silently sent; image/PDF/video uses the separate guarded Local media route after installation."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"WHATSAPP_STATE_CONFLICT\",\"message\":\"Synthetic refusal; inspect the actual response before retrying.\"}}}"},{"id":"95e30a7a-ac06-c12f-7f0d-697c39e731e7","name":"SYNTHETIC 400 — invalid send request","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\"generation\":{{waGeneration}},\"idempotencyKey\":\"{{waIdempotencyKey}}\",\"recipient\":\"{{waRecipient}}\",\"text\":\"{{waText}}\"}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/messages","description":"Local PC/permitted LAN. Only with separately approved sender profile and recipient. Required: generation from current status, idempotencyKey (1–128 chars), recipient 7–15 international digits, nonblank direct text <=16,384 UTF-8 bytes. One voucher-level sender profile; no inferred account. Set all wa* fixtures and confirmWhatsAppSend=yes for exactly one authorized send; guard consumes it. HTTP 202 means durable acceptance only, not socket write, server ACK, delivery or read. Poll operation/events. Lost/uncertain result: inspect same operation/key; NEVER automatically resend or invent a new key. Groups, arbitrary media formats and history are not silently sent; image/PDF/video uses the separate guarded Local media route after installation."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"WHATSAPP_INVALID_REQUEST\",\"message\":\"Synthetic refusal; inspect the actual response before retrying.\"}}}"}],"_postman_id":"57548c8b-8356-7ec7-3240-ca26266678b3"},{"name":"WhatsApp operation lookup — metadata read","id":"183269fe-9a25-bea0-3a1d-8aa38ed4e5e9","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/operations/{{waOperationId}}","description":"<p>Local PC/permitted LAN; metadata-only lookup for a previously accepted operation belonging to selected profile. Missing fixtures skip before send. No message body, key or QR. Phases distinguish accepted, durable intent, socket write, server ACK, delivered, read and unknown; a 200 response is not proof of delivery.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","whatsapp","profiles","{{waProfileId}}","operations","{{waOperationId}}"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"1668bd05-b51e-1f34-cb39-25ad552776b5","name":"SYNTHETIC 200 — operation metadata","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/operations/{{waOperationId}}","description":"Local PC/permitted LAN; metadata-only lookup for a previously accepted operation belonging to selected profile. Missing fixtures skip before send. No message body, key or QR. Phases distinguish accepted, durable intent, socket write, server ACK, delivered, read and unknown; a 200 response is not proof of delivery."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"operationId\": \"22222222-2222-4222-8222-222222222222\",\n    \"profileId\": \"11111111-1111-4111-8111-111111111111\",\n    \"generation\": 1,\n    \"phase\": \"accepted\"\n  },\n  \"metadata\": {}\n}"},{"id":"09852f13-c920-2cf3-34db-4c9065c2928e","name":"SYNTHETIC 404 — operation missing","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/operations/{{waOperationId}}","description":"Local PC/permitted LAN; metadata-only lookup for a previously accepted operation belonging to selected profile. Missing fixtures skip before send. No message body, key or QR. Phases distinguish accepted, durable intent, socket write, server ACK, delivered, read and unknown; a 200 response is not proof of delivery."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\"success\":false,\"data\":null,\"metadata\":{\"error\":{\"code\":\"WHATSAPP_NOT_FOUND\",\"message\":\"Synthetic refusal; inspect the actual response before retrying.\"}}}"}],"_postman_id":"183269fe-9a25-bea0-3a1d-8aa38ed4e5e9"},{"name":"WhatsApp events — metadata cursor read","id":"ad7b61ec-489f-248e-1eba-7a843af06738","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/events?after={{waAfter}}","description":"<p>Local PC/permitted LAN; after is a nonnegative event ID; at most 200 metadata events. Set waAfter=0 for first page, then last eventId to continue. Does not expose inbound body or keys. Empty array is a valid success. Missing/invalid cursor or profile fixture skips before send.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","whatsapp","profiles","{{waProfileId}}","events"],"host":["{{baseUrl}}"],"query":[{"key":"after","value":"{{waAfter}}"}],"variable":[]}},"response":[{"id":"44b38713-24d0-3f24-b0aa-1a8839447423","name":"SYNTHETIC 200 — cursor page","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/events?after={{waAfter}}","host":["{{baseUrl}}"],"path":["api","v1","whatsapp","profiles","{{waProfileId}}","events"],"query":[{"key":"after","value":"{{waAfter}}"}]},"description":"Local PC/permitted LAN; after is a nonnegative event ID; at most 200 metadata events. Set waAfter=0 for first page, then last eventId to continue. Does not expose inbound body or keys. Empty array is a valid success. Missing/invalid cursor or profile fixture skips before send."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [\n    {\n      \"eventId\": 1,\n      \"profileId\": \"11111111-1111-4111-8111-111111111111\",\n      \"generation\": 1,\n      \"operationId\": \"22222222-2222-4222-8222-222222222222\",\n      \"kind\": \"accepted\"\n    }\n  ],\n  \"metadata\": {}\n}"}],"_postman_id":"ad7b61ec-489f-248e-1eba-7a843af06738"},{"name":"⚠ Send WhatsApp media — image/PDF/video, one-send","id":"475c5a1b-1d9e-d125-6a85-098743f74ba8","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"generation\":{{waGeneration}},\"idempotencyKey\":\"{{waIdempotencyKey}}\",\"recipient\":\"{{waRecipient}}\",\"kind\":\"{{waMediaKind}}\",\"mimeType\":\"{{waMediaMimeType}}\",\"fileName\":\"{{waMediaFileName}}\",\"contentBase64\":\"{{waMediaContentBase64}}\"}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/messages/media","description":"<p>LOCAL PC/permitted LAN, source-only route: installed internal 0.0.20 does not have media send. Use a separately authorized sender profile and recipient. Required generation, idempotencyKey, recipient, kind=image/document/video, exact mimeType, safe fileName and canonical contentBase64 (1–2 MiB). PNG/JPEG, PDF and progressive H.264 MP4 only; video additionally needs waMediaWidth/waMediaHeight/waMediaSeconds. Optional waMediaCaption: leave unset/empty for no caption; nonempty sends a caption (&lt;=512 chars and 2048 UTF-8 bytes). The pre-request script constructs JSON safely, skips missing/invalid fixtures and consumes confirmWhatsAppSend=yes once. Set waMediaContentBase64 as a temporary local fixture; do not save real customer media, numbers or keys in the shared collection/environment. HTTP 202 is durable acceptance, not delivery/playback. Lookup operation/events; uncertain outcome must be reconciled, never blindly resent. Exact expected refusals use waExpectedStatus plus waExpectedCode. Cloud Relay is not implemented for this route.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","whatsapp","profiles","{{waProfileId}}","messages","media"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"20c3b189-9100-ec6b-5398-50b3606f509c","name":"SYNTHETIC 202 — image with caption; durable only","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"generation\":{{waGeneration}},\"idempotencyKey\":\"{{waIdempotencyKey}}\",\"recipient\":\"{{waRecipient}}\",\"kind\":\"{{waMediaKind}}\",\"mimeType\":\"{{waMediaMimeType}}\",\"fileName\":\"{{waMediaFileName}}\",\"contentBase64\":\"{{waMediaContentBase64}}\"}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/messages/media","description":"LOCAL PC/permitted LAN, source-only route: installed internal 0.0.20 does not have media send. Use a separately authorized sender profile and recipient. Required generation, idempotencyKey, recipient, kind=image/document/video, exact mimeType, safe fileName and canonical contentBase64 (1–2 MiB). PNG/JPEG, PDF and progressive H.264 MP4 only; video additionally needs waMediaWidth/waMediaHeight/waMediaSeconds. Optional waMediaCaption: leave unset/empty for no caption; nonempty sends a caption (<=512 chars and 2048 UTF-8 bytes). The pre-request script constructs JSON safely, skips missing/invalid fixtures and consumes confirmWhatsAppSend=yes once. Set waMediaContentBase64 as a temporary local fixture; do not save real customer media, numbers or keys in the shared collection/environment. HTTP 202 is durable acceptance, not delivery/playback. Lookup operation/events; uncertain outcome must be reconciled, never blindly resent. Exact expected refusals use waExpectedStatus plus waExpectedCode. Cloud Relay is not implemented for this route."},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"operationId\": \"22222222-2222-4222-8222-222222222222\",\n    \"profileId\": \"11111111-1111-4111-8111-111111111111\",\n    \"generation\": 1,\n    \"phase\": \"accepted\"\n  },\n  \"metadata\": {}\n}"},{"id":"69c798f3-339b-69fd-f73c-d03ea094755c","name":"SYNTHETIC 202 — image without caption; durable only","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"generation\":{{waGeneration}},\"idempotencyKey\":\"{{waIdempotencyKey}}\",\"recipient\":\"{{waRecipient}}\",\"kind\":\"{{waMediaKind}}\",\"mimeType\":\"{{waMediaMimeType}}\",\"fileName\":\"{{waMediaFileName}}\",\"contentBase64\":\"{{waMediaContentBase64}}\"}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/messages/media","description":"LOCAL PC/permitted LAN, source-only route: installed internal 0.0.20 does not have media send. Use a separately authorized sender profile and recipient. Required generation, idempotencyKey, recipient, kind=image/document/video, exact mimeType, safe fileName and canonical contentBase64 (1–2 MiB). PNG/JPEG, PDF and progressive H.264 MP4 only; video additionally needs waMediaWidth/waMediaHeight/waMediaSeconds. Optional waMediaCaption: leave unset/empty for no caption; nonempty sends a caption (<=512 chars and 2048 UTF-8 bytes). The pre-request script constructs JSON safely, skips missing/invalid fixtures and consumes confirmWhatsAppSend=yes once. Set waMediaContentBase64 as a temporary local fixture; do not save real customer media, numbers or keys in the shared collection/environment. HTTP 202 is durable acceptance, not delivery/playback. Lookup operation/events; uncertain outcome must be reconciled, never blindly resent. Exact expected refusals use waExpectedStatus plus waExpectedCode. Cloud Relay is not implemented for this route."},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"operationId\": \"22222222-2222-4222-8222-222222222222\",\n    \"profileId\": \"11111111-1111-4111-8111-111111111111\",\n    \"generation\": 1,\n    \"phase\": \"accepted\"\n  },\n  \"metadata\": {}\n}"},{"id":"60157f8a-b37e-d033-7a05-a672b3098df2","name":"SYNTHETIC 400 — invalid media format","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"generation\":{{waGeneration}},\"idempotencyKey\":\"{{waIdempotencyKey}}\",\"recipient\":\"{{waRecipient}}\",\"kind\":\"{{waMediaKind}}\",\"mimeType\":\"{{waMediaMimeType}}\",\"fileName\":\"{{waMediaFileName}}\",\"contentBase64\":\"{{waMediaContentBase64}}\"}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/messages/media","description":"LOCAL PC/permitted LAN, source-only route: installed internal 0.0.20 does not have media send. Use a separately authorized sender profile and recipient. Required generation, idempotencyKey, recipient, kind=image/document/video, exact mimeType, safe fileName and canonical contentBase64 (1–2 MiB). PNG/JPEG, PDF and progressive H.264 MP4 only; video additionally needs waMediaWidth/waMediaHeight/waMediaSeconds. Optional waMediaCaption: leave unset/empty for no caption; nonempty sends a caption (<=512 chars and 2048 UTF-8 bytes). The pre-request script constructs JSON safely, skips missing/invalid fixtures and consumes confirmWhatsAppSend=yes once. Set waMediaContentBase64 as a temporary local fixture; do not save real customer media, numbers or keys in the shared collection/environment. HTTP 202 is durable acceptance, not delivery/playback. Lookup operation/events; uncertain outcome must be reconciled, never blindly resent. Exact expected refusals use waExpectedStatus plus waExpectedCode. Cloud Relay is not implemented for this route."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"WHATSAPP_INVALID_REQUEST\",\n      \"message\": \"Use the documented WhatsApp request shape and bounded values.\"\n    }\n  }\n}"},{"id":"a080d659-2cfe-8dc8-f549-7ed7adb35722","name":"SYNTHETIC 409 — stale generation or changed idempotency content","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"generation\":{{waGeneration}},\"idempotencyKey\":\"{{waIdempotencyKey}}\",\"recipient\":\"{{waRecipient}}\",\"kind\":\"{{waMediaKind}}\",\"mimeType\":\"{{waMediaMimeType}}\",\"fileName\":\"{{waMediaFileName}}\",\"contentBase64\":\"{{waMediaContentBase64}}\"}"},"url":"{{baseUrl}}/api/v1/whatsapp/profiles/{{waProfileId}}/messages/media","description":"LOCAL PC/permitted LAN, source-only route: installed internal 0.0.20 does not have media send. Use a separately authorized sender profile and recipient. Required generation, idempotencyKey, recipient, kind=image/document/video, exact mimeType, safe fileName and canonical contentBase64 (1–2 MiB). PNG/JPEG, PDF and progressive H.264 MP4 only; video additionally needs waMediaWidth/waMediaHeight/waMediaSeconds. Optional waMediaCaption: leave unset/empty for no caption; nonempty sends a caption (<=512 chars and 2048 UTF-8 bytes). The pre-request script constructs JSON safely, skips missing/invalid fixtures and consumes confirmWhatsAppSend=yes once. Set waMediaContentBase64 as a temporary local fixture; do not save real customer media, numbers or keys in the shared collection/environment. HTTP 202 is durable acceptance, not delivery/playback. Lookup operation/events; uncertain outcome must be reconciled, never blindly resent. Exact expected refusals use waExpectedStatus plus waExpectedCode. Cloud Relay is not implemented for this route."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"WHATSAPP_STATE_CONFLICT\",\n      \"message\": \"The profile, generation, idempotency key or current account state does not permit this action.\"\n    }\n  }\n}"}],"_postman_id":"475c5a1b-1d9e-d125-6a85-098743f74ba8"},{"name":"⚠ Send WhatsApp accounting form TEXT — one-send","id":"50b5d6ac-f33f-ee0c-39d9-34138c5dd896","request":{"auth":{"type":"noauth","isInherited":false},"method":"POST","header":[],"body":{"mode":"formdata","formdata":[{"value":"{{waFormSenderName}}","key":"senderId","type":"text"},{"value":"{{waRecipient}}","key":"receiverId","type":"text"},{"value":"{{waFormText}}","key":"messageText","type":"text"},{"value":"{{localApiToken}}","key":"authToken","type":"text"}]},"url":"{{baseUrl}}/api/v1/whatsapp/send-form","description":"<p>LOCAL PC/permitted LAN only. The installed internal 0.0.22 includes this Local route. The existing Local API token VALUE goes in authToken multipart form field. No Authorization header is sent. senderId is exact case-sensitive profile display name; receiverId is 7–15 international digits. messageText is required nonblank direct text. Set senderId, receiverId and messageText before Send; the API returns validation errors. Optional idempotencyKey (1–128 chars) may be added when supported by the caller. Without it, never blindly retry a lost/uncertain send; inspect operation/events. HTTP 202 means durable acceptance, not delivery. For refusals, inspect the server's HTTP status and error code; this collection runs no assertion script. No Cloud Relay route.</p>\n","urlObject":{"path":["api","v1","whatsapp","send-form"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"733655b3-e2a6-e126-d603-f4a0e9265070","name":"SYNTHETIC 202 — form text accepted","originalRequest":{"auth":{"type":"noauth"},"method":"POST","header":[],"body":{"mode":"formdata","formdata":[{"value":"{{waFormSenderName}}","key":"senderId","type":"text"},{"value":"{{waRecipient}}","key":"receiverId","type":"text"},{"value":"{{waFormText}}","key":"messageText","type":"text"},{"value":"{{localApiToken}}","key":"authToken","type":"text"}]},"url":"{{baseUrl}}/api/v1/whatsapp/send-form","description":"LOCAL PC/permitted LAN only. Source route is not installed in internal 0.0.20. The existing Local API token VALUE goes in authToken multipart form field. No Authorization header is sent. senderId is exact case-sensitive profile display name; receiverId is 7–15 international digits. messageText is required nonblank direct text. Set temporary waFormSenderName, waRecipient, waFormText, then confirmWhatsAppSend=yes for one approved send; confirmation is consumed. Optional idempotencyKey (1–128 chars) may be added when supported by the caller. Without it, never blindly retry a lost/uncertain send; inspect operation/events. HTTP 202 means durable acceptance, not delivery. Expected refusals use waExpectedStatus and waExpectedCode together. No Cloud Relay route."},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"operationId\": \"00000000-0000-4000-8000-000000000001\",\n    \"profileId\": \"00000000-0000-4000-8000-000000000002\",\n    \"generation\": 1,\n    \"phase\": \"accepted\"\n  },\n  \"metadata\": {}\n}"},{"id":"f6c4443c-cd47-a652-8f40-f0b41adebce1","name":"SYNTHETIC 401 — missing or invalid authToken","originalRequest":{"auth":{"type":"noauth"},"method":"POST","header":[],"body":{"mode":"formdata","formdata":[{"value":"{{waFormSenderName}}","key":"senderId","type":"text"},{"value":"{{waRecipient}}","key":"receiverId","type":"text"},{"value":"{{waFormText}}","key":"messageText","type":"text"},{"value":"{{localApiToken}}","key":"authToken","type":"text"}]},"url":"{{baseUrl}}/api/v1/whatsapp/send-form","description":"LOCAL PC/permitted LAN only. Source route is not installed in internal 0.0.20. The existing Local API token VALUE goes in authToken multipart form field. No Authorization header is sent. senderId is exact case-sensitive profile display name; receiverId is 7–15 international digits. messageText is required nonblank direct text. Set temporary waFormSenderName, waRecipient, waFormText, then confirmWhatsAppSend=yes for one approved send; confirmation is consumed. Optional idempotencyKey (1–128 chars) may be added when supported by the caller. Without it, never blindly retry a lost/uncertain send; inspect operation/events. HTTP 202 means durable acceptance, not delivery. Expected refusals use waExpectedStatus and waExpectedCode together. No Cloud Relay route."},"status":"Unauthorized","code":401,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"UNAUTHORIZED\",\n      \"message\": \"A valid authToken form field is required.\"\n    },\n    \"requestId\": \"00000000-0000-4000-8000-000000000004\"\n  }\n}"}],"_postman_id":"50b5d6ac-f33f-ee0c-39d9-34138c5dd896"},{"name":"⚠ Send WhatsApp accounting form IMAGE/PDF — one-send","id":"244cc804-e25c-6c2d-637b-46e5c1fc5d56","request":{"auth":{"type":"noauth","isInherited":false},"method":"POST","header":[],"body":{"mode":"formdata","formdata":[{"type":"text","value":"{{waFormSenderName}}","key":"senderId"},{"type":"text","value":"{{waRecipient}}","key":"receiverId"},{"type":"text","value":"{{waFormText}}","key":"messageText"},{"type":"text","value":"{{localApiToken}}","key":"authToken"},{"type":"file","value":"","key":"uploadFile"}]},"url":"{{baseUrl}}/api/v1/whatsapp/send-form","description":"<p>LOCAL PC/permitted LAN only. The installed internal 0.0.22 includes this Local route. Same Local API token value in authToken multipart form field; this request sends no Authorization header. senderId is exact case-sensitive profile display name; receiverId is 7–15 international digits. Select one local PNG/JPEG/PDF uploadFile (1 byte–2 MiB). messageText is required but may be empty for no caption; nonempty is caption (&lt;=512 chars / 2048 UTF-8 bytes). Set senderId, receiverId and messageText before Send; the API returns validation errors. Optional idempotencyKey can be added if caller supports it; without a stable key, do not blindly retry uncertain outcomes. HTTP 202 is durable acceptance only; inspect operation/events. For refusals, inspect the server's HTTP status and error code; this collection runs no assertion script. No Cloud Relay route.</p>\n<p>Postman file check: this shared request intentionally stores no local file path. Before Send, select an existing local PNG/JPEG/PDF of 1 byte–2 MiB for uploadFile and inspect any warning beside the filename. Do not set Content-Type/boundary manually; Postman supplies it. If the file part is absent, this same route accepts messageText as a text-only message and can still return 202. To confirm a media send, read GET /api/v1/whatsapp/queue for the returned operationId: kind must be image or document (not text), then inspect its phase. A 202 accepted response alone does not prove the file was uploaded or delivered.</p>\n","urlObject":{"path":["api","v1","whatsapp","send-form"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"16f2d548-4adf-e94c-fab4-2096cc15a89c","name":"SYNTHETIC 202 — form image/PDF accepted","originalRequest":{"auth":{"type":"noauth"},"method":"POST","header":[],"body":{"mode":"formdata","formdata":[{"type":"text","value":"{{waFormSenderName}}","key":"senderId"},{"type":"text","value":"{{waRecipient}}","key":"receiverId"},{"type":"text","value":"{{waFormText}}","key":"messageText"},{"type":"text","value":"{{localApiToken}}","key":"authToken"},{"type":"file","value":"","key":"uploadFile"}]},"url":"{{baseUrl}}/api/v1/whatsapp/send-form","description":"LOCAL PC/permitted LAN only. Source route is not installed in internal 0.0.20. Same Local API token value in authToken multipart form field; this request sends no Authorization header. senderId is exact case-sensitive profile display name; receiverId is 7–15 international digits. Select one local PNG/JPEG/PDF uploadFile (1 byte–2 MiB). messageText is required but may be empty for no caption; nonempty is caption (<=512 chars / 2048 UTF-8 bytes). Temporary waFormSenderName, waRecipient and waFormText must be set, with confirmWhatsAppSend=yes for ONE approved send. Optional idempotencyKey can be added if caller supports it; without a stable key, do not blindly retry uncertain outcomes. HTTP 202 is durable acceptance only; inspect operation/events. Expected refusals require waExpectedStatus and waExpectedCode. No Cloud Relay route."},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":null,"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"operationId\": \"00000000-0000-4000-8000-000000000003\",\n    \"profileId\": \"00000000-0000-4000-8000-000000000002\",\n    \"generation\": 1,\n    \"phase\": \"accepted\"\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"244cc804-e25c-6c2d-637b-46e5c1fc5d56"}],"id":"524047d9-12cc-6c00-15db-d4846013dd47","description":"<p>LOCAL PC only: installed internal 0.0.20 has direct text; the separate media route is source-only, not installed or public, with no Cloud Relay route. All responses/examples are synthetic. Keep master/profile off unless a separately authorized real-account test names the profiles and approved recipients. Status and metadata reads are safe; account controls/QR/send use explicit one-send guards. 202 is durable acceptance, not server ACK/delivery. Unknown send outcomes must be reconciled, never automatically reposted. Do not save real QR, numbers, keys, bodies or session material in this collection.</p>\n","_postman_id":"524047d9-12cc-6c00-15db-d4846013dd47","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Company backups (this PC only)","item":[{"name":"List company backup plans","id":"50ea154b-5383-ead9-8f7d-a2a93b1202ed","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/company-backups/plans","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Read only. Shows plans and live activity. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","plans"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"aba885a2-7a9a-2192-ff2c-34edb7953ee6","name":"200 — empty plans (synthetic)","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/company-backups/plans","description":"Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Read only. Shows plans and live activity. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {}\n}"}],"_postman_id":"50ea154b-5383-ead9-8f7d-a2a93b1202ed"},{"name":"⚠ Create company backup plan — changes settings","id":"a8a866ef-3e3c-5905-bdf5-acc38aeec52b","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP_DEMO\",\n  \"destinationKind\": \"folder\",\n  \"folderRoot\": \"C:\\\\AI-Zeny-Backup-DEMO\",\n  \"scheduleKind\": \"manual\",\n  \"retentionDays\": 30\n}"},"url":"{{baseUrl}}/api/v1/company-backups/plans","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Changes AI Zeny settings; checks the destination. Synthetic company code must be replaced intentionally. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","plans"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"ea5472c2-797a-cf86-211d-f7afb1d075f7","name":"403 — plan does not include company backups","originalRequest":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP_DEMO\",\n  \"destinationKind\": \"folder\",\n  \"folderRoot\": \"C:\\\\AI-Zeny-Backup-DEMO\",\n  \"scheduleKind\": \"manual\",\n  \"retentionDays\": 30\n}"},"url":"{{baseUrl}}/api/v1/company-backups/plans","description":"Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Changes AI Zeny settings; checks the destination. Synthetic company code must be replaced intentionally. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts."},"status":"Forbidden","code":403,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PLAN_FEATURE_NOT_INCLUDED\",\n      \"message\": \"Company backups are not included in this plan.\"\n    }\n  }\n}"}],"_postman_id":"a8a866ef-3e3c-5905-bdf5-acc38aeec52b"},{"name":"Get company backup plan","id":"cc56c4c2-c0d3-5def-676f-d4d992b7ba0f","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/company-backups/plans/00000000000000000000000000000001","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Read only. Replace the synthetic plan ID. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","plans","00000000000000000000000000000001"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"cc56c4c2-c0d3-5def-676f-d4d992b7ba0f"},{"name":"⚠ Update company backup plan — changes settings","id":"48b4bc97-997b-5888-9b4a-f88cecf8c933","request":{"method":"PUT","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP_DEMO\",\n  \"destinationKind\": \"folder\",\n  \"folderRoot\": \"C:\\\\AI-Zeny-Backup-DEMO\",\n  \"scheduleKind\": \"manual\",\n  \"retentionDays\": 30,\n  \"expectedRevision\": 1\n}"},"url":"{{baseUrl}}/api/v1/company-backups/plans/00000000000000000000000000000001","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Changes AI Zeny settings. Replace synthetic ID and check current revision. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","plans","00000000000000000000000000000001"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"48b4bc97-997b-5888-9b4a-f88cecf8c933"},{"name":"⚠ Delete company backup plan — changes settings","id":"02b62a89-0f32-4855-c83a-bcb0317c98a9","request":{"method":"DELETE","header":[],"url":"{{baseUrl}}/api/v1/company-backups/plans/00000000000000000000000000000001?expectedRevision=1","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Deletes plan only; backup history and packages remain. Replace synthetic ID. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","plans","00000000000000000000000000000001"],"host":["{{baseUrl}}"],"query":[{"key":"expectedRevision","value":"1"}],"variable":[]}},"response":[],"_postman_id":"02b62a89-0f32-4855-c83a-bcb0317c98a9"},{"name":"⚠ Back up company now — reads BUSY and writes destination","id":"c9dfc325-3161-3717-cfb3-381633e55184","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/company-backups/plans/00000000000000000000000000000001/run","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Starts or queues a real encrypted company backup. Native BUSY/database and destination effects; never blindly retry uncertain operations. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","plans","00000000000000000000000000000001","run"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"a0a4b428-a59a-ad37-4fc5-d1e7e2223109","name":"202 — backup started","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/company-backups/plans/00000000000000000000000000000001/run","description":"Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Starts or queues a real encrypted company backup. Native BUSY/database and destination effects; never blindly retry uncertain operations. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts."},"status":"Accepted","code":202,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"state\": \"started\",\n    \"jobId\": \"00000000000000000000000000000003\"\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"c9dfc325-3161-3717-cfb3-381633e55184"},{"name":"⚠ Cancel company backup job — changes runtime","id":"31d5c23b-95de-a022-eea0-e2924847609d","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/company-backups/plans/00000000000000000000000000000001/cancel","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Requests cancellation of a running backup. Never retry cancellation blindly. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","plans","00000000000000000000000000000001","cancel"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"31d5c23b-95de-a022-eea0-e2924847609d"},{"name":"⚠ Pause company backup schedule — changes settings","id":"b0ebad20-cf77-712c-082f-528614732402","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"expectedRevision\": 1\n}"},"url":"{{baseUrl}}/api/v1/company-backups/plans/00000000000000000000000000000001/pause","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Pauses schedule; manual run remains available. Replace synthetic ID and revision. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","plans","00000000000000000000000000000001","pause"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"b0ebad20-cf77-712c-082f-528614732402"},{"name":"⚠ Resume company backup schedule — changes settings","id":"bb5773db-2dd9-6b2f-4992-a8d6062c9375","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"expectedRevision\": 1\n}"},"url":"{{baseUrl}}/api/v1/company-backups/plans/00000000000000000000000000000001/resume","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Resumes schedule; may cause backup work. Replace synthetic ID and revision. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","plans","00000000000000000000000000000001","resume"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"bb5773db-2dd9-6b2f-4992-a8d6062c9375"},{"name":"List retained company backup copies","id":"35eee021-4545-c225-4ff3-28ff89de69a6","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/company-backups/plans/00000000000000000000000000000001/retained","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Read only. Shows retained copies and their state. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","plans","00000000000000000000000000000001","retained"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"35eee021-4545-c225-4ff3-28ff89de69a6"},{"name":"⚠ Publish retained copy — uploads externally","id":"81894c87-7fd1-3ddd-4c54-eb7094671dc5","request":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/company-backups/plans/00000000000000000000000000000001/retained/00000000000000000000000000000002/publish","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Attempts external destination publication of a retained encrypted copy. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","plans","00000000000000000000000000000001","retained","00000000000000000000000000000002","publish"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"d904bd8a-f3d5-eebe-e30f-846e035d6347","name":"200 — retained copy published","originalRequest":{"method":"POST","header":[],"url":"{{baseUrl}}/api/v1/company-backups/plans/00000000000000000000000000000001/retained/00000000000000000000000000000002/publish","description":"Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Attempts external destination publication of a retained encrypted copy. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"copyId\": \"00000000000000000000000000000002\",\n    \"outcome\": \"published\"\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"81894c87-7fd1-3ddd-4c54-eb7094671dc5"},{"name":"⚠ Save retained copy — writes folder","id":"e17f532d-433b-c787-c029-e605b8cbdd79","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"folder\": \"C:\\\\AI-Zeny-Backup-DEMO\"\n}"},"url":"{{baseUrl}}/api/v1/company-backups/plans/00000000000000000000000000000001/retained/00000000000000000000000000000002/save","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Writes a retained encrypted copy to a selected folder; replace synthetic paths and IDs. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","plans","00000000000000000000000000000001","retained","00000000000000000000000000000002","save"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"e17f532d-433b-c787-c029-e605b8cbdd79"},{"name":"⚠ Discard retained copy — permanent action","id":"4476ffc4-353a-15b8-967d-235ca8509e45","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"confirm\": true\n}"},"url":"{{baseUrl}}/api/v1/company-backups/plans/00000000000000000000000000000001/retained/00000000000000000000000000000002/discard","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Permanently discards a retained copy; confirm intended ID before Send. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","plans","00000000000000000000000000000001","retained","00000000000000000000000000000002","discard"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"4476ffc4-353a-15b8-967d-235ca8509e45"},{"name":"List unknown destination candidates","id":"7ba49dcb-765b-5535-ae2f-1b5bf3a471c4","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/company-backups/plans/00000000000000000000000000000001/ledger/candidates","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Read only. Lists destination objects absent from this PC's ledger. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","plans","00000000000000000000000000000001","ledger","candidates"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"7ba49dcb-765b-5535-ae2f-1b5bf3a471c4"},{"name":"⚠ Adopt destination candidates — changes ledger","id":"d10f8049-e747-d3e3-8a2e-13ce53bb5bba","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"ids\": [\n    \"00000000000000000000000000000002\"\n  ],\n  \"confirm\": true\n}"},"url":"{{baseUrl}}/api/v1/company-backups/plans/00000000000000000000000000000001/ledger/adopt","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Adds selected existing destination objects to the ledger; replace synthetic IDs. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","plans","00000000000000000000000000000001","ledger","adopt"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"d10f8049-e747-d3e3-8a2e-13ce53bb5bba"},{"name":"⚠ Check folder destination — may create marker","id":"ce9917cd-5505-fa2b-165c-1f524dc470dd","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"kind\": \"folder\",\n  \"root\": \"C:\\\\AI-Zeny-Backup-DEMO\"\n}"},"url":"{{baseUrl}}/api/v1/company-backups/destinations/check","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Probes destination and may create an ownership marker; use an intended test folder. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","destinations","check"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"01ed8d35-8c2b-7b24-0053-887c29fab813","name":"200 — folder check","originalRequest":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"kind\": \"folder\",\n  \"root\": \"C:\\\\AI-Zeny-Backup-DEMO\"\n}"},"url":"{{baseUrl}}/api/v1/company-backups/destinations/check","description":"Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Probes destination and may create an ownership marker; use an intended test folder. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"writable\": true,\n    \"freeBytes\": 10737418240,\n    \"pathClass\": \"local\",\n    \"created\": false,\n    \"code\": null,\n    \"message\": null\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"ce9917cd-5505-fa2b-165c-1f524dc470dd"},{"name":"Check SQL backup prerequisites — server access","id":"29d6eb27-d5a9-0cad-de63-d533193eadf5","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP_DEMO\",\n  \"stagingServerPath\": \"C:\\\\AI-Zeny-SQL-Staging-DEMO\",\n  \"stagingLocalPath\": \"C:\\\\AI-Zeny-SQL-Staging-DEMO\"\n}"},"url":"{{baseUrl}}/api/v1/company-backups/sql/check","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Checks SQL service permissions and backup prerequisites; no company backup is started. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","sql","check"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"29d6eb27-d5a9-0cad-de63-d533193eadf5"},{"name":"List company backup jobs","id":"56400345-ba7f-ff2d-9147-b9e97b641304","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/company-backups/jobs?page=1&pageSize=25","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Read only. Optional planId, companyCode and status filters. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","jobs"],"host":["{{baseUrl}}"],"query":[{"key":"page","value":"1"},{"key":"pageSize","value":"25"}],"variable":[]}},"response":[],"_postman_id":"56400345-ba7f-ff2d-9147-b9e97b641304"},{"name":"Get company backup job","id":"8a3b6077-3104-4c16-4b3d-b0e44350c438","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/company-backups/jobs/00000000000000000000000000000003","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Read only. Shows job, artifact and retained copy. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","jobs","00000000000000000000000000000003"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"8a3b6077-3104-4c16-4b3d-b0e44350c438"},{"name":"Get company backup public keys","id":"fe7fc60e-c433-e5cb-77f6-68d1c86c79ea","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/company-backups/key","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Read only. Public key metadata; never contains a private key. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","key"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"1e8ab6a0-abc3-24ab-0dd6-841da5287014","name":"200 — no active key","originalRequest":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/company-backups/key","description":"Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Read only. Public key metadata; never contains a private key. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"active\": null,\n    \"earlier\": []\n  },\n  \"metadata\": {}\n}"}],"_postman_id":"fe7fc60e-c433-e5cb-77f6-68d1c86c79ea"},{"name":"⚠ Set company backup public key — changes settings","id":"8cb2922e-93ba-a775-1ba7-871d3785a371","request":{"method":"PUT","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"publicKeyPem\": \"REPLACE_WITH_RSA_3072_SPKI_PUBLIC_PEM\",\n  \"source\": \"imported\"\n}"},"url":"{{baseUrl}}/api/v1/company-backups/key","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Changes active public key. Supply only the intended RSA-3072 public PEM; never private key or password. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","key"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"40699e25-5b4b-812f-c349-67585fc7ac54","name":"400 — invalid public key","originalRequest":{"method":"PUT","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"publicKeyPem\": \"REPLACE_WITH_RSA_3072_SPKI_PUBLIC_PEM\",\n  \"source\": \"imported\"\n}"},"url":"{{baseUrl}}/api/v1/company-backups/key","description":"Local PC loopback only; Bearer {{localApiToken}} through collection auth. Documentation-only synthetic example. Changes active public key. Supply only the intended RSA-3072 public PEM; never private key or password. Response uses success/data/metadata envelope; see docs/LOCAL-API.md §5ax. No Postman scripts."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"COMPANY_BACKUP_KEY_INVALID\",\n      \"message\": \"A valid RSA-3072 SPKI public key is required.\",\n      \"field\": \"publicKeyPem\"\n    }\n  }\n}"}],"_postman_id":"8cb2922e-93ba-a775-1ba7-871d3785a371"},{"name":"Get company backup retention status","id":"5dc7c4e4-5427-bf6d-5887-4723a28f0bc0","request":{"method":"GET","header":[],"url":"{{baseUrl}}/api/v1/company-backups/retention?planId=00000000000000000000000000000001","description":"<p>Local PC loopback only; Bearer {{localApiToken}} through collection auth. Read only. planId is required; replace this synthetic plan ID. Response shows the plan's last retention run and failed removals. See docs/LOCAL-API.md §5ax. No Postman scripts.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","company-backups","retention"],"host":["{{baseUrl}}"],"query":[{"key":"planId","value":"00000000-0000-0000-0000-000000000001"}],"variable":[]}},"response":[],"_postman_id":"5dc7c4e4-5427-bf6d-5887-4723a28f0bc0"}],"id":"7ea62949-de93-0aa6-73dd-1e7f1bfcd82b","_postman_id":"7ea62949-de93-0aa6-73dd-1e7f1bfcd82b","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ Tax documents — government or native effects","item":[{"name":"⚠ REAL GOVERNMENT EFFECT — Generate e-Invoice (Local)","id":"76aa4e73-6b75-d89a-13cb-3eec2b150cb4","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"synthetic-einvoice-intent-01"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP0003\",\n  \"financialYear\": \"2026\",\n  \"voucherCode\": 123,\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/e-invoice-generate","description":"<p>Static synthetic contract example only. Pressing Send can submit a real e-Invoice to the government and persist native BUSY state for the referenced voucher. Replace every synthetic identifier with a verified, authorized fresh voucher before use. No Postman scripts, automatic retries, or confirmation guard. HTTP 202 with queue:true means accepted for later processing, not generated. If the outcome is uncertain, do not retry; reconcile the original voucher/provider. Cloud relay route is pending a separate implementation.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","e-invoice-generate"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"76aa4e73-6b75-d89a-13cb-3eec2b150cb4"},{"name":"⚠ REAL GOVERNMENT EFFECT — Generate e-Way Bill (Local)","id":"d1799f7c-6ae0-6524-b226-d0b58884f21c","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"X-Request-Id","value":"synthetic-ewb-intent-01"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP0003\",\n  \"financialYear\": \"2026\",\n  \"voucherCode\": 123,\n  \"queue\": false\n}"},"url":"{{baseUrl}}/api/v1/e-way-bill-generate","description":"<p>Static synthetic contract example only. Pressing Send can submit a real e-Way Bill to the government and persist native BUSY state for the referenced voucher. Replace every synthetic identifier with a verified, authorized fresh voucher before use. No Postman scripts or automatic retries. HTTP 202 with queue:true means accepted for later processing, not generated. If the outcome is uncertain, reconcile the original voucher/provider; never change request ID to bypass a hold. Cloud relay route is pending a separate implementation.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","e-way-bill-generate"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"d1799f7c-6ae0-6524-b226-d0b58884f21c"},{"name":"⚠ NATIVE PROVIDER/FILE EFFECT — Existing e-Way Bill PDF (Local)","id":"b75ecf85-3a0b-9844-1075-74d2df5aa70a","request":{"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"COMP0003\",\n  \"financialYear\": \"2026\",\n  \"voucherCode\": 123\n}"},"url":"{{baseUrl}}/api/v1/e-way-bill-pdf","description":"<p>Static synthetic contract example only. This route exports an existing saved e-Way Bill as a PDF via BUSY's native provider and file output; it does not generate a new e-Way Bill. It can still affect native/provider state. Replace synthetic identifiers with a verified authorized voucher before pressing Send. No Postman scripts or automatic retries. A successful response carries fileName, mimeType, byteLength, sha256, pages, padded contentBase64 and metadata. 409 means no complete saved EWB or unsafe output; 502 native refusal; 504 unknown export outcome requires reconciliation. Cloud relay route is pending a separate implementation.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["api","v1","e-way-bill-pdf"],"host":["{{baseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"b75ecf85-3a0b-9844-1075-74d2df5aa70a"}],"id":"29a08732-ddd8-6262-36c7-65fad2f6807d","_postman_id":"29a08732-ddd8-6262-36c7-65fad2f6807d","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}}],"id":"7d92b685-ab16-4a4d-a85f-62292c04071f","description":"<p><strong>Local — requests sent directly to the PC</strong> (the AI Zeny Host's Local API on port 8801).</p>\n<ul>\n<li><strong>Base URL:</strong> <code>{{baseUrl}}</code> (<code>http://127.0.0.1:8801</code> on this PC) or <code>{{lanBaseUrl}}</code> from another computer on the LAN. Every route starts <code>/api/v1/</code>.</li>\n<li><strong>Authentication:</strong> <code>Authorization: Bearer {{localApiToken}}</code> (collection auth; AI Zeny → BUSY Data → Local API → Reveal / Copy token). Only <code>/api/v1/health</code> is public.</li>\n<li><strong>Who can call:</strong> this PC and its local network (<code>403 LOCAL_NETWORK_ONLY</code> otherwise).</li>\n<li><strong>Answer:</strong> always <code>{ success, data, metadata }</code>; errors have <code>data: null</code> and <code>metadata.error { code, message, field? }</code>.</li>\n</ul>\n<p><strong>Folder names say what a request does, whatever its HTTP method:</strong> <em>(read only)</em> folders never change anything — most are POST only because they carry a JSON body. <strong>⚠ … WRITES TO BUSY</strong> folders create or change BUSY accounting data (masters, sales orders). <strong>⚠ PC Settings &amp; Management</strong> changes AI Zeny itself (companies, scripts, schedules, token), never BUSY. Every ⚠ request is skipped unless <code>confirmMutating</code> = <code>yes</code> and resets it after one send. Voucher <strong>Create</strong> (writes) and Voucher <strong>PDFs</strong> (prints an existing voucher) are separate folders.</p>\n","_postman_id":"7d92b685-ab16-4a4d-a85f-62292c04071f","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Cloud Relay (online PC via Pusher)","item":[{"name":"Health & Status (read only)","item":[{"name":"Ping","id":"0e10ce7b-10c1-2ee0-48cd-f7ec027f8bec","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/ping","description":"<p><strong>Cloud</strong> · <code>GET {{cloudBaseUrl}}/v1/ping</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> answered by the cloud itself; it does not reach the PC (use it to check the token and whether the PC is connected).\n<strong>Answer:</strong> the cloud's JSON answer.</p>\n<hr />\n<p>Proves the token and names its organization. Answered by the cloud itself; the PC is not involved.</p>\n","urlObject":{"path":["v1","ping"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"0e10ce7b-10c1-2ee0-48cd-f7ec027f8bec"},{"name":"Device status","id":"bc61983c-5b3b-d763-6e38-ea0568a770de","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/device/status","description":"<p><strong>Cloud</strong> · <code>GET {{cloudBaseUrl}}/v1/device/status</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> answered by the cloud itself; it does not reach the PC (use it to check the token and whether the PC is connected).\n<strong>Answer:</strong> the cloud's JSON answer.</p>\n<hr />\n<p>Whether the organization's PC is reachable. Answered by the cloud itself.</p>\n","urlObject":{"path":["v1","device","status"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"bc61983c-5b3b-d763-6e38-ea0568a770de"},{"name":"Companies","id":"9bb7a22e-7c1c-c0a2-275f-63d9ed84ebc2","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/companies","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/companies</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>companies.list</code>: the BUSY companies configured on the PC that the organization's scope allows, with their allowed financial years.</p>\n","urlObject":{"path":["v1","companies"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"9bb7a22e-7c1c-c0a2-275f-63d9ed84ebc2"},{"name":"Trial balance","id":"50ad308f-0064-0305-7f54-40e3e1945252","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYears\": [\"{{financialYear}}\"],\n  \"parameters\": {\n    \"fromDate\": \"{{financialYear}}-04-01\"\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/reports/trial-balance","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/reports/trial-balance</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>reports.trial-balance</code>.</p>\n<p>Body: companyCode (string), financialYears (array of four-digit starting years, for example <code>[\"2026\"]</code> = April 2026 – March 2027; <code>\"2026-27\"</code> is refused) and parameters (fromDate, optionally toDate, YYYY-MM-DD). The body uses <code>{{financialYear}}</code> directly.</p>\n<p>data: <code>{ requestId, companyCode, financialYears, result: { columns, rows, summary } }</code> — financialYears is echoed as four-digit years; rows tagged by year, one summary per year.</p>\n","urlObject":{"path":["v1","reports","trial-balance"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"50ad308f-0064-0305-7f54-40e3e1945252"}],"id":"c7a6d53a-e404-4aec-85da-76a64ec5c8e1","description":"<p>Cloud reachability, the PC's connection state, the organization's companies and the trial balance. Read only.</p>\n","_postman_id":"c7a6d53a-e404-4aec-85da-76a64ec5c8e1","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Master Reads (read only)","item":[{"name":"Units of measure","id":"2b8caa85-16cb-b981-a008-be37d1d8dfad","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"search\": \"kg\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/busy/units/query","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/busy/units/query</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/busy/units/query</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.units.query</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.units.query</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally search (string), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): search none; page 1; pageSize 100.</p>\n<p>Paging: page 1–10000 (default 1), pageSize 1–200 (default 100); at most 1000 units per year.</p>\n<p>data: array of { unitId, name, alias, printName }</p>\n","urlObject":{"path":["v1","busy","units","query"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"2b8caa85-16cb-b981-a008-be37d1d8dfad"},{"name":"Branches","id":"704abab8-5752-a365-f0b4-6a347ff28b3a","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/branches","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/branches</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/branches</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.branches.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.branches.list</code>.</p>\n<p>Body: companyCode (string) and financialYear (four-digit string).</p>\n<p>data: array of { branch_id, branch_name }</p>\n","urlObject":{"path":["v1","branches"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"704abab8-5752-a365-f0b4-6a347ff28b3a"},{"name":"Categories","id":"4583f5e1-011d-6d7f-d69d-4b46d7a21763","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/categories","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/categories</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/categories</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.categories.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.categories.list</code>.</p>\n<p>Body: companyCode (string) and financialYear (four-digit string).</p>\n<p>data: array of { category_id, category_name }</p>\n","urlObject":{"path":["v1","categories"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"4583f5e1-011d-6d7f-d69d-4b46d7a21763"},{"name":"Product groups","id":"549501e2-d534-ba78-447a-055bac5348ad","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/product-groups","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/product-groups</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/product-groups</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.product-groups.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.product-groups.list</code>.</p>\n<p>Body: companyCode (string) and financialYear (four-digit string).</p>\n<p>data: array of { product_group_id, product_group_name }</p>\n","urlObject":{"path":["v1","product-groups"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"549501e2-d534-ba78-447a-055bac5348ad"},{"name":"Material centres","id":"aea44031-041a-4886-c774-9c5424275057","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/material-centers","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/material-centers</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/material-centers</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.material-centers.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.material-centers.list</code>.</p>\n<p>Body: companyCode (string) and financialYear (four-digit string).</p>\n<p>data: array of { mc_id, mc_name, mc_alias, mc_print_name }</p>\n","urlObject":{"path":["v1","material-centers"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"aea44031-041a-4886-c774-9c5424275057"},{"name":"Sale types","id":"6f9e97b4-fa93-ce53-8a83-c738e6e9870f","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sale-types","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/sale-types</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/sale-types</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.sale-types.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.sale-types.list</code>.</p>\n<p>Body: companyCode (string) and financialYear (four-digit string).</p>\n<p>data: array of { sale_type_id, sale_type_name, sale_type_alias, sale_type_print_name }</p>\n","urlObject":{"path":["v1","sale-types"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"6f9e97b4-fa93-ce53-8a83-c738e6e9870f"},{"name":"Salesmen","id":"7e85283b-c75a-94d2-496c-de1d335a3229","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/salesmen","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/salesmen</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/salesmen</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.salesmen.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.salesmen.list</code>.</p>\n<p>Body: companyCode (string) and financialYear (four-digit string).</p>\n<p>data: array of { salesman_id, salesman_name, salesman_alias, mobile_number, whatsapp_number, email }</p>\n","urlObject":{"path":["v1","salesmen"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"7e85283b-c75a-94d2-496c-de1d335a3229"},{"name":"Voucher series","id":"676b6cda-6514-b3f5-209a-43c6236a01f8","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/voucher-series","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/voucher-series</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/voucher-series</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.voucher-series.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.voucher-series.list</code>.</p>\n<p>Body: companyCode (string) and financialYear (four-digit string).</p>\n<p>data: array of { voucher_series_id, voucher_series_name }</p>\n","urlObject":{"path":["v1","voucher-series"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"676b6cda-6514-b3f5-209a-43c6236a01f8"},{"name":"Item parameters","id":"371a71e6-4e3a-5418-e69d-af6a5132cf3d","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/parameters","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/parameters</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/parameters</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.parameters.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.parameters.list</code>.</p>\n<p>Body: companyCode (string) and financialYear (four-digit string).</p>\n<p>data: array of { id, name } (id = position in binary name order)</p>\n","urlObject":{"path":["v1","parameters"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"371a71e6-4e3a-5418-e69d-af6a5132cf3d"},{"name":"Products","id":"35f2e4a3-d07b-06b9-fc2c-afebbceb13ce","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"inStockOnly\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/products","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/products</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/products</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.products.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.products.list</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally materialCenterIds (array of numbers), includePendingSalesOrder, inStockOnly, parametersStock, optionalFields, erpCategories (booleans) and priceCategory (number).</p>\n<p>Defaults (on the PC): every switch false; materialCenterIds all centres; priceCategory none.</p>\n<p>data: array of product rows (product_id, product_name, product_alias, product_print_name, prices, group, units, material centre, tax, stock, discounts, description lines, product_alias_1…15, audit fields; parameters / optional_fields / erp_categories only when their switch is true)</p>\n<p>A full catalogue can exceed the 2 MiB relay limit (<code>RESPONSE_TOO_LARGE</code>); use <em>Products, one page</em> then.</p>\n","urlObject":{"path":["v1","products"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"35f2e4a3-d07b-06b9-fc2c-afebbceb13ce"},{"name":"Products, one page","id":"8c4ac21e-a7d5-b1d5-3bc9-8d4a369e16ed","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/products-pagination","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/products-pagination</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/products-pagination</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>page</code>, <code>pageSize</code> · operation <code>busy.products.page</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.products.page</code>.</p>\n<p>Body: the product members (companyCode (string), financialYear (four-digit string), and optionally materialCenterIds (array of numbers), includePendingSalesOrder, inStockOnly, parametersStock, optionalFields, erpCategories (booleans) and priceCategory (number)) and page and pageSize (numbers).</p>\n<p>Defaults (on the PC): every switch false; materialCenterIds all centres; priceCategory none (page and pageSize have no default).</p>\n<p>Paging: page and pageSize required, each ≥ 1, no maximum.</p>\n<p>data: array of product rows (product_id, product_name, product_alias, product_print_name, prices, group, units, material centre, tax, stock, discounts, description lines, product_alias_1…15, audit fields; parameters / optional_fields / erp_categories only when their switch is true)</p>\n","urlObject":{"path":["v1","products-pagination"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"8c4ac21e-a7d5-b1d5-3bc9-8d4a369e16ed"},{"name":"Product search","id":"90c1a340-b69f-20cc-8553-5463f7df1727","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"bolt\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/products-search","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/products-search</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/products-search</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.products.search</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.products.search</code>.</p>\n<p>Body: the product members (companyCode (string), financialYear (four-digit string), and optionally materialCenterIds (array of numbers), includePendingSalesOrder, inStockOnly, parametersStock, optionalFields, erpCategories (booleans) and priceCategory (number)) and optionally name, printName, alias, multipleAlias, groupName (strings) and groupId (number).</p>\n<p>Defaults (on the PC): every switch false; every search member none (none = every product).</p>\n<p>data: array of product rows (product_id, product_name, product_alias, product_print_name, prices, group, units, material centre, tax, stock, discounts, description lines, product_alias_1…15, audit fields; parameters / optional_fields / erp_categories only when their switch is true)</p>\n","urlObject":{"path":["v1","products-search"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"90c1a340-b69f-20cc-8553-5463f7df1727"},{"name":"Configured optional product fields","id":"445a46f3-73ef-21e1-efcf-bdb4adcdcc5b","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/products-of-config","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/products-of-config</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/products-of-config</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.products-of-config.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.products-of-config.list</code>.</p>\n<p>Body: companyCode (string) and financialYear (four-digit string).</p>\n<p>data: array of { field_no, of_column, field_name, field_type, decimal_places, maintain_master_database }</p>\n","urlObject":{"path":["v1","products-of-config"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"445a46f3-73ef-21e1-efcf-bdb4adcdcc5b"},{"name":"Product group hierarchy","id":"24dd1090-46f2-b544-6958-b7acf0516064","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/product-groups-hierarchy","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/product-groups-hierarchy</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/product-groups-hierarchy</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.product-groups.hierarchy</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.product-groups.hierarchy</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally rootGroupId (number).</p>\n<p>Defaults (on the PC): rootGroupId none (the whole hierarchy).</p>\n<p>data: { root_group_id, hierarchy: [ { group_id, group_name, parent_group_id, direct_product_count, children, descendant_group_ids, total_product_count } ] }</p>\n","urlObject":{"path":["v1","product-groups-hierarchy"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"24dd1090-46f2-b544-6958-b7acf0516064"},{"name":"Price-category prices","id":"536b519f-57b2-ce4a-c9f0-2a32385cc6c1","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"priceCategories\": [1, 2, 3]\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/products-multiple-prices","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/products-multiple-prices</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/products-multiple-prices</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.products.multiple-prices</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.products.multiple-prices</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally priceCategories (array of numbers).</p>\n<p>Defaults (on the PC): priceCategories 1–10.</p>\n<p>data: array of { product_id, product_name, then per category a…z: {p}_product_sales_price, {p}_product_mrp, {p}_product_sales_discount }</p>\n","urlObject":{"path":["v1","products-multiple-prices"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"536b519f-57b2-ce4a-c9f0-2a32385cc6c1"},{"name":"Latest date-wise prices","id":"02f59b46-7c4e-7bc1-63d9-c9580a35997d","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/products-multiple-prices-datewise","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/products-multiple-prices-datewise</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/products-multiple-prices-datewise</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.products.multiple-prices-datewise</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.products.multiple-prices-datewise</code>.</p>\n<p>Body: companyCode (string) and financialYear (four-digit string).</p>\n<p>data: array of { product_id, product_name, latest_pricing_date, then per identifier a, b, …: {p}_price_identifier, {p}_product_sales_price, {p}_product_mrp, {p}_product_sales_discount }</p>\n","urlObject":{"path":["v1","products-multiple-prices-datewise"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"02f59b46-7c4e-7bc1-63d9-c9580a35997d"},{"name":"Customer group hierarchy","id":"5ea1ee85-41c5-834f-8ef3-98e67fa788ad","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/customer-groups-hierarchy","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/customer-groups-hierarchy</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/customer-groups-hierarchy</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.customer-groups.hierarchy</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.customer-groups.hierarchy</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally rootGroupId (number).</p>\n<p>Defaults (on the PC): rootGroupId none (the whole hierarchy).</p>\n<p>data: { root_group_id, hierarchy: [ { group_id, group_name, parent_group_id, direct_customer_count, children, descendant_group_ids, total_customer_count } ] }</p>\n","urlObject":{"path":["v1","customer-groups-hierarchy"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"5ea1ee85-41c5-834f-8ef3-98e67fa788ad"},{"name":"Customers","id":"193aa708-92d8-5bcc-d593-557a6126cd09","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/customers","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/customers</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/customers</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.customers.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.customers.list</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally pendingSalesOrderOnly (boolean).</p>\n<p>Defaults (on the PC): pendingSalesOrderOnly false.</p>\n<p>data: array of { customer_id, customer_name, customer_alias, group_id, group_name, mobile_number, email_id, whatsapp_number, address_line_1…4, pin_code, country, state, gst_number, pan_number, station, opening_balance, balance, closing_balance, salesman_id, salesman_name, salesman_mobile_number, salesman_whatsapp_number, price_category }</p>\n","urlObject":{"path":["v1","customers"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"193aa708-92d8-5bcc-d593-557a6126cd09"},{"name":"One customer","id":"11ff83a8-72c2-84cc-e89c-5adf915f4319","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/customer","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/customer</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/customer</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.customers.get</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.customers.get</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string) and customerId (number).</p>\n<p>data: one-element array of { customer_id, customer_name, customer_alias, group_id, group_name, mobile_number, email_id, whatsapp_number, address_line_1…4, pin_code, country, state, gst_number, pan_number, station, opening_balance, balance, closing_balance, salesman_id, salesman_name, salesman_mobile_number, salesman_whatsapp_number, price_category }</p>\n","urlObject":{"path":["v1","customer"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"11ff83a8-72c2-84cc-e89c-5adf915f4319"},{"name":"Is this WhatsApp number a customer?","id":"7b563821-bc36-cc6f-177c-c4696208431f","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"whatsappNumber\": \"+91 98765 43210\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/validate-whatsapp","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/validate-whatsapp</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/validate-whatsapp</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>whatsappNumber</code> · operation <code>busy.customers.validate-whatsapp</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.customers.validate-whatsapp</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string) and whatsappNumber (string).</p>\n<p>data: { isRegistered, matchedCustomers: [ { customer_id, customer_name, customer_alias, price_category, email_address, whatsapp_number } ] }</p>\n","urlObject":{"path":["v1","validate-whatsapp"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"7b563821-bc36-cc6f-177c-c4696208431f"},{"name":"Is this e-mail address a customer?","id":"12624d90-5464-b0ed-fc03-95e2cebf71e3","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"emailAddress\": \"accounts@example.com\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/validate-email","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/validate-email</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/validate-email</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>emailAddress</code> · operation <code>busy.customers.validate-email</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.customers.validate-email</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string) and emailAddress (string).</p>\n<p>data: { isRegistered, matchedCustomers: [ … ] }</p>\n","urlObject":{"path":["v1","validate-email"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"12624d90-5464-b0ed-fc03-95e2cebf71e3"},{"name":"Suppliers","id":"56e3c1ed-7521-7915-5db8-35df3963efe0","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/suppliers","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/suppliers</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/suppliers</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.suppliers.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.suppliers.list</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally supplierId (number), search (string), includeContactDetails (boolean), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): supplierId none; search none; includeContactDetails false; page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100).</p>\n<p>data: array of { supplier_id, supplier_name, supplier_alias, supplier_print_name, supplier_group_id, supplier_group_name, purchase_voucher_count, purchase_return_voucher_count, purchase_order_count, has_purchase_vouchers, has_purchase_returns, has_purchase_orders, gst_number, mobile_number }</p>\n","urlObject":{"path":["v1","suppliers"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"56e3c1ed-7521-7915-5db8-35df3963efe0"},{"name":"Optional-field definitions","id":"4e432177-95b7-e77d-6217-6be479223525","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/optional-field-definitions","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/optional-field-definitions</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/optional-field-definitions</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.optional-fields.definitions</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.\n<strong>Status (2026-10-23):</strong> deployed and live (release <code>790395a</code>). The PC side is in released AI Zeny 0.0.14 (Windows <code>a20701b</code>, installed service-account acceptance passed); an earlier PC build answers <code>502 DEVICE_ERROR</code>.</p>\n<hr />\n<p>Signed command <code>busy.optional-fields.definitions</code>.</p>\n<p>Body: <code>companyCode, financialYear.</code></p>\n<p>The account and item (product) optional fields BUSY has defined for the company and year — definitions are BUSY settings of each year, so read them for the year you write.</p>\n<p>data: <code>{ accounts: [field], products: [field] }</code> in slot order; field = <code>{ slot (\"OF1\"-\"OF10\", the key the master writes use), name, kind (\"text\" | \"dropdown\" | \"number\" | \"date\" | \"yesNo\" | \"other\"), busyType, busySubDetail, decimalPlaces, writable, notWritableReason (when not writable), values ([{ code, name }], dropdowns only) }</code>.</p>\n<p>metadata: <code>apiVersion, operation, requestId, companyCode, financialYear, accountFieldCount, productFieldCount, elapsedMs</code>.</p>\n<p><code>writable</code> says whether the master writes accept a value (accounts and products alike: text, dropdown, whole number, date, Yes/No, on Access and on SQL Server with a SQL login). A master write never creates a dropdown value: add one with \"⚠ BUSY product dropdown value – create\" or \"⚠ BUSY account dropdown value – create\" in Cloud Relay → ⚠ Master Create &amp; Modify. Fields are never created through the API.</p>\n","urlObject":{"path":["v1","optional-field-definitions"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"4e432177-95b7-e77d-6217-6be479223525"}],"id":"e3be5b97-563d-4880-8862-6f2c004e49c7","description":"<p>The same master reads as Local, relayed to the PC. Read only. These are POST requests only because they carry a JSON body; none of them changes BUSY or AI Zeny.</p>\n","_postman_id":"e3be5b97-563d-4880-8862-6f2c004e49c7","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Accounting & Reports (read only)","item":[{"name":"Customer dashboard","id":"44109886-db63-2aab-87eb-f3da440ee53c","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/customer-dashboard","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/customer-dashboard</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/customer-dashboard</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.customers.dashboard</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.customers.dashboard</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string) and customerId (number).</p>\n<p>Defaults (on the PC): calculationDate today (UTC, the PC clock).</p>\n<p>data: { customer_id, customer_name, customer_print_name, closing_balance, pending_balance, due_balance, credit_limit, total_sales_amount, total_receipts_amount, total_sale_returns_amount }</p>\n","urlObject":{"path":["v1","customer-dashboard"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"44109886-db63-2aab-87eb-f3da440ee53c"},{"name":"Customers with pending bills","id":"21c9730f-c5e4-fdb6-f230-3867f08370c5","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/customers-pending-bills","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/customers-pending-bills</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/customers-pending-bills</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.customers.pending-bills</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.customers.pending-bills</code>.</p>\n<p>Body: companyCode (string) and financialYear (four-digit string).</p>\n<p>Defaults (on the PC): calculationDate today (UTC, the PC clock).</p>\n<p>data: array of { customer_id, customer_name, customer_alias, group_id, group_name, mobile_number, email_id, whatsapp_number, address_line_1…4, pin_code, country, state, gst_number, pan_number, station, opening_balance, balance, closing_balance, salesman_id, salesman_name, salesman_mobile_number, salesman_whatsapp_number, price_category, total_pending_amount, total_due_amount }</p>\n","urlObject":{"path":["v1","customers-pending-bills"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"21c9730f-c5e4-fdb6-f230-3867f08370c5"},{"name":"One customer's pending bills","id":"275c66ad-6a86-7507-4805-fed8f0ffa3ef","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"isDue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/customer-pending-bills","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/customer-pending-bills</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/customer-pending-bills</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.customers.bills.pending</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.customers.bills.pending</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), customerId (number), and optionally isDue (boolean).</p>\n<p>Defaults (on the PC): isDue false; calculationDate today (UTC, the PC clock).</p>\n<p>data: array of { user_id, account_name, salesman_code, transaction_date, transaction_date_raw, transaction_type, reference_number, invoice_number, total_reference_amount, total_pending_amount, is_due, due_date, due_date_raw, days_until_due, days_overdue }</p>\n","urlObject":{"path":["v1","customer-pending-bills"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"275c66ad-6a86-7507-4805-fed8f0ffa3ef"},{"name":"Bill-wise statement","id":"6f47d4ab-5468-2026-2573-4988d3d996ff","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/customer-bill-wise-statement","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/customer-bill-wise-statement</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/customer-bill-wise-statement</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.customers.bills.statement</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.customers.bills.statement</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string) and customerId (number).</p>\n<p>Defaults (on the PC): calculationDate today (UTC, the PC clock).</p>\n<p>data: array of { reference_number, transaction_type, transaction_date, transaction_date_raw, total_reference_amount, receivable_amount, payable_amount, due_date, due_date_raw, due_days, ref_code, voucher_code, voucher_type, voucher_series_code, signed_balance }</p>\n","urlObject":{"path":["v1","customer-bill-wise-statement"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"6f47d4ab-5468-2026-2573-4988d3d996ff"},{"name":"Supplier ledger","id":"c697c98d-b4e9-e850-b24e-bd3660d0e814","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"supplierId\": {{supplierId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/supplier-ledger","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/supplier-ledger</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/supplier-ledger</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>supplierId</code> · operation <code>busy.suppliers.ledger</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.suppliers.ledger</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), supplierId (number), and optionally fromDate and toDate (strings, YYYY-MM-DD), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate 1 April and toDate 31 March of the year; page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100).</p>\n<p>data: { rows: [ { ledger_row_id, voucher_code, voucher_type_id, voucher_number, voucher_date, line_number, supplier_name, supplier_id, financial_year_opening_balance, debit, credit, running_balance } ], summary: { financial_year_opening_balance, period_opening_balance, period_debit, period_credit, closing_balance } }</p>\n","urlObject":{"path":["v1","supplier-ledger"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"c697c98d-b4e9-e850-b24e-bd3660d0e814"},{"name":"Supplier pending bills","id":"45f1da3f-43ba-1d16-9dc2-f0c7daa1cfab","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"status\": \"open\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/supplier-pending-bills","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/supplier-pending-bills</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/supplier-pending-bills</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.suppliers.bills.pending</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.suppliers.bills.pending</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally supplierId (number), status (open, closed or all), includeCredits (boolean), asOfDate (string, YYYY-MM-DD), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): status open; includeCredits true; asOfDate today (UTC, the PC clock) clamped into the year; page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100).</p>\n<p>data: array of { supplier_id, supplier_name, bill_reference_code, reference_number, origin_voucher_code, origin_voucher_type_id, bill_date, due_date, original_amount, pending_amount, allocation_count, allocated_amount, status, days_overdue, is_unadjusted_credit, allocations: [ … ] }</p>\n","urlObject":{"path":["v1","supplier-pending-bills"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"45f1da3f-43ba-1d16-9dc2-f0c7daa1cfab"},{"name":"Customer ledger (one or more years)","id":"16d88811-0473-608b-ebc2-a407e188043c","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/customer-ledger","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/customer-ledger</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/customer-ledger</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.customers.ledger</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.customers.ledger</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string) and customerId (number), and optionally additionalFinancialYear (string of comma-separated four-digit years), startDate and endDate (strings, YYYY-MM-DD).</p>\n<p>Defaults (on the PC): additionalFinancialYear none; startDate and endDate unbounded.</p>\n<p>data: array of { user_id, opening_balance, user_id2, transaction_date_iso, formatted_date, voucher_type, voucher_no, account_name, debit, credit, voucher_code, on_account, financial_year }</p>\n<p>Optional: <code>additionalFinancialYear</code> (comma-separated four-digit years, e.g. \"2025\"), each an allowed year of the company; every year is read from its own BUSY database and is part of the signed scope.</p>\n","urlObject":{"path":["v1","customer-ledger"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"16d88811-0473-608b-ebc2-a407e188043c"},{"name":"Single item ledger","id":"32340d0d-e377-3cfe-448e-1e3a24c9a5ec","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": {{productId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/single-item-ledger","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/single-item-ledger</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/single-item-ledger</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>productId</code> · operation <code>busy.items.ledger</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.items.ledger</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string) and productId (number), and optionally fromDate and toDate (YYYY-MM-DD), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate/toDate the year's bounds (each side on its own); page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100); the summary covers the whole range.</p>\n<p>data: { product: { … }, summary: { opening, in, out, closing quantities and amounts, tran4 control totals }, ledger: [ { date, voucher_type, voucher_type_id, voucher_number, voucher_code, sr_no, party, material centre, particulars, quantity_in, amount_in, quantity_out, amount_out, balance_quantity, balance_amount } ] }</p>\n","urlObject":{"path":["v1","single-item-ledger"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"32340d0d-e377-3cfe-448e-1e3a24c9a5ec"},{"name":"One item's sales per customer","id":"7de7819a-8d51-9ce7-2a75-38a12ec38e36","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": {{productId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-analysis-single-item","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/sales-analysis-single-item</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/sales-analysis-single-item</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>productId</code> · operation <code>busy.sales-analysis.item</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.sales-analysis.item</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string) and productId (number), and optionally fromDate and toDate (YYYY-MM-DD), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate/toDate the year's bounds (each side on its own); page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100); the summary covers the whole range.</p>\n<p>data: { item: { … }, rows: [ one per customer: sale, return and net quantities and amounts, average_price, voucher counts ], summary: { … totals } }</p>\n","urlObject":{"path":["v1","sales-analysis-single-item"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"7de7819a-8d51-9ce7-2a75-38a12ec38e36"},{"name":"One customer's sales per product","id":"2b670548-6109-0778-ea26-08cceef2bcf5","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-analysis-single-customer","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/sales-analysis-single-customer</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/sales-analysis-single-customer</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.sales-analysis.customer</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.sales-analysis.customer</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string) and customerId (number), and optionally fromDate and toDate (YYYY-MM-DD), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate/toDate the year's bounds (each side on its own); page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100); the summary covers the whole range.</p>\n<p>data: { customer: { customer_id, customer_name, customer_alias }, rows: [ one per product: main and alternative unit quantities, amounts, average prices, voucher counts ], summary: { … totals } }</p>\n","urlObject":{"path":["v1","sales-analysis-single-customer"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"2b670548-6109-0778-ea26-08cceef2bcf5"},{"name":"Customer's active and dropped products (one or more years)","id":"1cdc1e76-b09a-92c9-ecf5-a31eecd65217","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/customer-product-analytics","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/customer-product-analytics</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/customer-product-analytics</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.customers.product-analytics</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.customers.product-analytics</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string) and customerId (number), and optionally additionalFinancialYear (string of comma-separated four-digit years), fromDate and toDate (YYYY-MM-DD), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): additionalFinancialYear none; fromDate/toDate the primary year's bounds; page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100); the summary covers the whole range; active then dropped products are one paged sequence.</p>\n<p>data: { customer: { … }, summary: { … }, active_products: [ … ], dropped_products: [ … with rates, frequency and daily, weekly, monthly trends ] }</p>\n<p>Optional: <code>additionalFinancialYear</code> (comma-separated four-digit years, e.g. \"2025\"), each an allowed year of the company; every year is read from its own BUSY database and is part of the signed scope.</p>\n","urlObject":{"path":["v1","customer-product-analytics"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"1cdc1e76-b09a-92c9-ecf5-a31eecd65217"},{"name":"Day-end summary","id":"748bb338-a5e8-d0e3-56cf-f04c71e6d4a0","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"date\": \"{{financialYear}}-04-10\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/day-end-report-summary","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/day-end-report-summary</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/day-end-report-summary</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.day-end.summary</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.day-end.summary</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and either date or both startDate and endDate (YYYY-MM-DD), and optionally cashMasterCode (number).</p>\n<p>Defaults (on the PC): cashMasterCode 1 (the date form has no default).</p>\n<p>data: array of exactly 10 rows { type, total_amount, cash_signed, party_signed, others_signed, total_amount_display, cash, party, others }</p>\n","urlObject":{"path":["v1","day-end-report-summary"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"748bb338-a5e8-d0e3-56cf-f04c71e6d4a0"},{"name":"Day-end detailed report","id":"214a8a04-af03-bd48-fb26-fa87670c2c94","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"startDate\": \"{{financialYear}}-04-01\",\n  \"endDate\": \"{{financialYear}}-04-07\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/day-end-report-detailed","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/day-end-report-detailed</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/day-end-report-detailed</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.day-end.detailed</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.day-end.detailed</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and either date or both startDate and endDate (YYYY-MM-DD).</p>\n<p>data: array of { type, date, date_raw, voucher_no, particulars, cash_signed, bank_signed, bank_od_signed, party_signed, others_signed, cash, bank, bank_od, party, others } (one complete answer, not paged)</p>\n","urlObject":{"path":["v1","day-end-report-detailed"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"214a8a04-af03-bd48-fb26-fa87670c2c94"},{"name":"Account monthly summary","id":"92eb8eec-c839-5ffb-0a53-30e82adaa966","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/account-monthly-summary","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/account-monthly-summary</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/account-monthly-summary</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.accounts.monthly-summary</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.accounts.monthly-summary</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally page and pageSize (numbers).</p>\n<p>Defaults (on the PC): page 1; pageSize 100 (always the whole year).</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100); totals cover every account.</p>\n<p>data: { rows: [ { account_id, account_name, opening, April–March debit and credit, closing, signed values } ], totals: { … } }</p>\n","urlObject":{"path":["v1","account-monthly-summary"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"92eb8eec-c839-5ffb-0a53-30e82adaa966"},{"name":"Account consolidated summary","id":"2895eede-1959-753a-ad9d-4f707afacd83","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-09-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/account-consolidated-summary","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/account-consolidated-summary</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/account-consolidated-summary</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.accounts.consolidated-summary</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.accounts.consolidated-summary</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally fromDate and toDate (YYYY-MM-DD; one alone means that one day), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate/toDate the whole year (one date alone = that one day); page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100); the summary covers the whole range.</p>\n<p>data: { rows: [ { account_id, account_name, parent_group_id, parent_group_name, opening_balance_dr, opening_balance_cr, debit_amount, credit_amount, closing_balance_dr, closing_balance_cr, note_text, opening_signed, closing_signed } ], totals: { … } }</p>\n","urlObject":{"path":["v1","account-consolidated-summary"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"2895eede-1959-753a-ad9d-4f707afacd83"},{"name":"Dashboard sales summary","id":"8fd8b6ae-0bff-79ee-1b46-a15bebdfd8df","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/dashboard-sales-summary","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/dashboard-sales-summary</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/dashboard-sales-summary</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.dashboard.sales-summary</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.dashboard.sales-summary</code>.</p>\n<p>Body: companyCode (string) and financialYear (four-digit string).</p>\n<p>data: { daily: [ … every day ], weekly: [ … W1–W53 ], monthly: [ … ], quarterly: [ … ], halfYearly: [ … ] } each with invoiceCount and totalSalesAmount</p>\n","urlObject":{"path":["v1","dashboard-sales-summary"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"8fd8b6ae-0bff-79ee-1b46-a15bebdfd8df"},{"name":"Dashboard sales trend","id":"099da9b8-cf99-fc6c-53eb-bc97ac45f97b","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"period\": \"monthly\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/dashboard-sales-trend","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/dashboard-sales-trend</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/dashboard-sales-trend</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.dashboard.sales-trend</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.dashboard.sales-trend</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally period (daily, weekly, monthly or yearly).</p>\n<p>Defaults (on the PC): period daily (the period is computed from today in India, on the PC).</p>\n<p>data: { period, startDate, endDate, total_sales_amount, total_sales_return_amount, total_receipt_amount }</p>\n<p>A period outside the selected year is <code>422 PERIOD_OUTSIDE_FINANCIAL_YEAR</code>.</p>\n","urlObject":{"path":["v1","dashboard-sales-trend"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"099da9b8-cf99-fc6c-53eb-bc97ac45f97b"},{"name":"Credit-line stage stream (NDJSON)","id":"c1fcec1b-8cf3-a627-71f3-0dd6bdeeec7e","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerIds\": [{{customerId}}],\n  \"billByBillMode\": \"standard\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/credit-line/line-stage-stream","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/credit-line/line-stage-stream</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/credit-line/line-stage-stream</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.credit-line.line-stage-stream</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.credit-line.line-stage-stream</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), customerIds and/or groupIds (arrays of numbers), and optionally billByBillMode, billByBillPdfConfig (object of booleans), customerOptionalFields (array of OF1-OF10), gracePeriodSource, gracePeriodDays (number), gracePeriodOptionalField, creditLineType, accountBlockOverdueDays and accountBlockExceedAmount (numbers).</p>\n<p>Defaults (on the PC): billByBillMode standard; billByBillPdfConfig every member true; customerOptionalFields none; gracePeriodSource project; gracePeriodDays 0; gracePeriodOptionalField the first customerOptionalFields entry (optional_field only); creditLineType both; account block none; calculationDate today in India (the PC clock).</p>\n<p>Answer: <code>application/x-ndjson</code>, one <code>{ success, data, metadata }</code> envelope per line — meta, then row or row_error and progress per customer, then done (or one final fatal_error). The cloud forwards the lines as the PC posts them (in ordered chunks). A refusal before the stream starts (for example an unknown group, 404) is an ordinary JSON envelope. Postman shows the whole answer once it ends.</p>\n","urlObject":{"path":["v1","credit-line","line-stage-stream"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"c1fcec1b-8cf3-a627-71f3-0dd6bdeeec7e"},{"name":"Inventory daybooks","id":"b2b8b8a1-d13f-4ce0-48f7-44615c750322","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-04-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/inventory-daybooks","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/inventory-daybooks</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/inventory-daybooks</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>fromDate</code>, <code>toDate</code> · operation <code>busy.inventory.daybooks</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.inventory.daybooks</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), fromDate and toDate (YYYY-MM-DD).</p>\n<p>data: array of { date, voucher_type, voucher_number, particular, item, quantity, unit }</p>\n","urlObject":{"path":["v1","inventory-daybooks"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"b2b8b8a1-d13f-4ce0-48f7-44615c750322"},{"name":"Receivables ageing analysis","id":"d56cd4e3-2b7a-8836-3a7a-e35f57076e5b","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"startDate\": \"{{financialYear}}-04-01\",\n  \"endDate\": \"{{financialYear}}-09-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/ageing-analysis-receivables","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/ageing-analysis-receivables</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/ageing-analysis-receivables</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>startDate</code>, <code>endDate</code> · operation <code>busy.receivables.ageing-analysis</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.receivables.ageing-analysis</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), customerId (number) or accountName (string), startDate and endDate (YYYY-MM-DD), and optionally statusDate (YYYY-MM-DD).</p>\n<p>Defaults (on the PC): statusDate endDate.</p>\n<p>data: array of pending bills with age buckets { reference_number, transaction_type, dates, total_amount, pending_amount, age_0_30_days … age_151_plus_days, age_days, ref_code, voucher_code, voucher_type, voucher_series_code, signed_balance }</p>\n","urlObject":{"path":["v1","ageing-analysis-receivables"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"d56cd4e3-2b7a-8836-3a7a-e35f57076e5b"},{"name":"Serial-number stock ageing","id":"405343cf-b2c5-b5d2-a4b9-643efb988ba1","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"asOnDate\": \"{{financialYear}}-09-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/stock-aging-receivable-issuable","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/stock-aging-receivable-issuable</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/stock-aging-receivable-issuable</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.inventory.stock-aging</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.inventory.stock-aging</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally asOnDate (YYYY-MM-DD), productId and materialCenterId (numbers).</p>\n<p>Defaults (on the PC): asOnDate today in India (the PC clock); productId and materialCenterId none.</p>\n<p>data: { rows: [ per product and material centre: brands, location, prices, oldest serials and dates, quantity, ages ], summary: { … } }</p>\n","urlObject":{"path":["v1","stock-aging-receivable-issuable"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"405343cf-b2c5-b5d2-a4b9-643efb988ba1"},{"name":"Unbilled customers","id":"5a921ce3-50c3-e91e-25f4-30f529f5d163","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"asOnDate\": \"{{financialYear}}-09-30\",\n  \"billingMode\": \"negative\",\n  \"billingRule\": \"lastBill\",\n  \"billingWindow\": \"30_days\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/unbilled-customers","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/unbilled-customers</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/unbilled-customers</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.customers.unbilled</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.customers.unbilled</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally asOnDate (YYYY-MM-DD), billingMode (positive or negative) with billingRule (lastBill or anyBill) and billingWindow (7_days, 30_days, quarter, 6_months or custom), and customDays (number) only with custom.</p>\n<p>Defaults (on the PC): asOnDate today in India (the PC clock); no billing filter.</p>\n<p>data: array of Sundry Debtors { customer_id, customer_name, groups, mobile_number, last/first bills and receipts (date, days, amount), closing_balance, closing_balance_type, closing_balance_display, closing_signed } (unpaged; amounts as two-decimal strings)</p>\n","urlObject":{"path":["v1","unbilled-customers"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"5a921ce3-50c3-e91e-25f4-30f529f5d163"},{"name":"Unbilled customer profile (one or more years)","id":"42142057-f74d-8413-e203-67e927d39410","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"type\": \"standard\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/unbilled-customer-profile","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/unbilled-customer-profile</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/unbilled-customer-profile</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.customers.unbilled-profile</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.customers.unbilled-profile</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string) and customerId (number), and optionally additionalFinancialYear (string of comma-separated four-digit years), fromDate and toDate together (YYYY-MM-DD) and type (standard or FIFO).</p>\n<p>Defaults (on the PC): additionalFinancialYear none; no period; type standard; reference date toDate, else today in India (the PC clock).</p>\n<p>data: { profile: { … }, analytics: { … }, trends: { monthly_sales_amount, monthly_receipt_amount, monthly_bill_count, monthly_collection_count }, transactions: [ … ], pending_bills: [ … ], due_bills: [ … ] }</p>\n<p>Optional: <code>additionalFinancialYear</code> (comma-separated four-digit years, e.g. \"2025\"), each an allowed year of the company; every year is read from its own BUSY database and is part of the signed scope.</p>\n","urlObject":{"path":["v1","unbilled-customer-profile"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"42142057-f74d-8413-e203-67e927d39410"},{"name":"Customer product-group discounts","id":"56659f78-7082-02ca-2fcf-02293710def0","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/customer-product-group-discounts","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/customer-product-group-discounts</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/customer-product-group-discounts</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.customers.product-group-discounts</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.customers.product-group-discounts</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), customerId (number) or customerName (string), and optionally page and pageSize (numbers).</p>\n<p>Defaults (on the PC): page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100).</p>\n<p>data: { rows: [ { discount_row_id, customer_id, customer_name, customer_alias, product_group_id, product_group_name, product_group_alias, effective_date, mrp, sale_price, sale_price_du, discount_percent, compound_discount_percent, d6_raw, d8_raw, d9_raw, c1_raw, c2_raw } ] }</p>\n","urlObject":{"path":["v1","customer-product-group-discounts"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"56659f78-7082-02ca-2fcf-02293710def0"}],"id":"a686be26-c279-44e9-af5d-5e07d812cb51","description":"<p>The same accounting reads and reports as Local, relayed to the PC (the credit-line stream answers NDJSON). Read only. These are POST requests only because they carry a JSON body; none of them changes BUSY or AI Zeny.</p>\n","_postman_id":"a686be26-c279-44e9-af5d-5e07d812cb51","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Registers, Orders & Invoices (read only)","item":[{"name":"Purchase register, product lines","id":"6946e979-8804-f29b-b4db-8ab71616e140","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-06-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-register-products","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/purchase-register-products</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/purchase-register-products</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.purchases.products</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.purchases.products</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally fromDate and toDate (YYYY-MM-DD), supplierId, productId, voucherId, materialCenterId (numbers), includeReturns and includeCancelled (booleans), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate/toDate the year's bounds; includeReturns true; includeCancelled false; page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100).</p>\n<p>data: array of purchase and purchase-return product lines with GST (voucher, supplier, purchase type, line_row_id, product, group, material centre, unit, quantity, prices, taxable_amount, gst_percent, gst_amount)</p>\n","urlObject":{"path":["v1","purchase-register-products"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"6946e979-8804-f29b-b4db-8ab71616e140"},{"name":"Pending purchase orders","id":"c7df02aa-7ea5-8d30-990f-5602bad9e86c","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"status\": \"open\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/pending-purchase-orders","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/pending-purchase-orders</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/pending-purchase-orders</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.purchases.orders.pending</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.purchases.orders.pending</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally fromDate, toDate and asOfDate (YYYY-MM-DD), supplierId and productId (numbers), referenceNumber (string), status (open, closed, over_linked or all), includeCancelled (boolean), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): no order-date filter; asOfDate today (UTC, the PC clock) clamped into the year; status open; includeCancelled false; page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100).</p>\n<p>data: array of purchase-order lines with their exact reference-code lifecycle (ordered, linked, pending, over-linked quantities, status)</p>\n","urlObject":{"path":["v1","pending-purchase-orders"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"c7df02aa-7ea5-8d30-990f-5602bad9e86c"},{"name":"Sales-return product lines","id":"d68a8575-080d-e1e7-b84c-7a82340b37e2","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-return-products","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/sales-return-products</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/sales-return-products</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.sales.returns.products</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.sales.returns.products</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally fromDate and toDate (YYYY-MM-DD), customerId, productId, voucherId (numbers), includeCancelled (boolean), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate/toDate the year's bounds; includeCancelled false; page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100).</p>\n<p>data: array of sales-return product lines with GST (voucher, customer, sale type, line_row_id, product, group, material centre, unit, return quantity, prices, taxable_amount, gst_percent, gst_amount)</p>\n","urlObject":{"path":["v1","sales-return-products"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"d68a8575-080d-e1e7-b84c-7a82340b37e2"},{"name":"One customer's sales register","id":"a97c1785-4f34-cd21-78c7-aa6a1f9b42d6","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/customer-sales-register","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/customer-sales-register</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/customer-sales-register</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.customers.sales-register</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.customers.sales-register</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), customerId (number), and optionally fromDate and toDate (YYYY-MM-DD), includeReturns and includeCancelled (booleans), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate/toDate the year's bounds; includeReturns true; includeCancelled false; page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100).</p>\n<p>data: { rows: [ { voucher_code, voucher_type_id, transaction_type, voucher_date, voucher_number, customer_id, customer_name, sale_type_id, sale_type_name, material_center_id, material_center_name, total_amount, sale_amount, taxable_amount, gst_amount } ], summary: { voucher_count, sales_total, returns_total, net_total, net_gst_amount } }</p>\n","urlObject":{"path":["v1","customer-sales-register"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"a97c1785-4f34-cd21-78c7-aa6a1f9b42d6"},{"name":"Sales register","id":"81f414a8-80df-2001-91ff-561f09b666f1","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-04-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-register","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/sales-register</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/sales-register</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.registers.sales</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.registers.sales</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally fromDate and toDate (YYYY-MM-DD; one alone means that one day), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate/toDate the whole year (one date alone = that one day); page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100); the summary covers the whole range.</p>\n<p>data: { rows: [ { date, voucher_code, voucher_type_id, voucher_number, customer_id, customer_name, gst_number, mobile_number, sale_type_id, sale_type_name, total_amount, sale_amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, other_amount, material_center_id, material_center_name, receipt_amount, status } ], summary: { total_amount_total, sale_amount_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total, other_amount_total, receipt_amount_total, total_tax_amount_total } }</p>\n","urlObject":{"path":["v1","sales-register"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"81f414a8-80df-2001-91ff-561f09b666f1"},{"name":"Purchase register","id":"abc080be-5f1d-6f7b-b7f1-211963f521dc","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-04-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-register","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/purchase-register</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/purchase-register</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.registers.purchase</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.registers.purchase</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally fromDate and toDate (YYYY-MM-DD; one alone means that one day), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate/toDate the whole year (one date alone = that one day); page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100); the summary covers the whole range.</p>\n<p>data: { rows: [ { date, voucher_code, voucher_type_id, voucher_number, account_id, account_name, gst_number, mobile_number, purchase_type_id, purchase_type_name, total_amount, purchase_amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, other_amount, material_center_id, material_center_name, payment_amount, status } ], summary: { total_amount_total, purchase_amount_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total, other_amount_total, payment_amount_total, total_tax_amount_total } }</p>\n","urlObject":{"path":["v1","purchase-register"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"abc080be-5f1d-6f7b-b7f1-211963f521dc"},{"name":"Sales-return (credit note) register","id":"1d9feb1d-f524-d675-a381-635c296bdc84","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-04-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-return-crnote-register","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/sales-return-crnote-register</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/sales-return-crnote-register</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.registers.sales-return</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.registers.sales-return</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally fromDate and toDate (YYYY-MM-DD; one alone means that one day), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate/toDate the whole year (one date alone = that one day); page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100); the summary covers the whole range.</p>\n<p>data: { rows: [ { date, voucher_code, voucher_type_id, voucher_number, customer_id, customer_name, gst_number, mobile_number, sale_type_id, sale_type_name, total_amount, sale_amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, other_amount, material_center_id, material_center_name, receipt_amount, status } ], summary: { total_amount_total, sale_amount_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total, other_amount_total, receipt_amount_total, total_tax_amount_total } }</p>\n","urlObject":{"path":["v1","sales-return-crnote-register"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"1d9feb1d-f524-d675-a381-635c296bdc84"},{"name":"Purchase-return (debit note) register","id":"df720383-56b0-f727-da6d-7184552163c1","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-04-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-return-drnote-register","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/purchase-return-drnote-register</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/purchase-return-drnote-register</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.registers.purchase-return</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.registers.purchase-return</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally fromDate and toDate (YYYY-MM-DD; one alone means that one day), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate/toDate the whole year (one date alone = that one day); page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100); the summary covers the whole range.</p>\n<p>data: { rows: [ { date, voucher_code, voucher_type_id, voucher_number, account_id, account_name, gst_number, mobile_number, purchase_type_id, purchase_type_name, total_amount, purchase_amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, other_amount, material_center_id, material_center_name, payment_amount, status } ], summary: { total_amount_total, purchase_amount_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total, other_amount_total, payment_amount_total, total_tax_amount_total } }</p>\n","urlObject":{"path":["v1","purchase-return-drnote-register"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"df720383-56b0-f727-da6d-7184552163c1"},{"name":"Payment register","id":"820c56b5-7fdd-4073-43f0-40470ffe2247","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-04-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/payment-register","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/payment-register</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/payment-register</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.registers.payment</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.registers.payment</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally fromDate and toDate (YYYY-MM-DD; one alone means that one day), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate/toDate the whole year (one date alone = that one day); page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100); the summary covers the whole range.</p>\n<p>data: { rows: [ { date, voucher_code, voucher_type_id, voucher_number, gst_nature_id, gst_nature, mode_id, mode_name, account_id, account_name, mobile_number, amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, short_narration, instrument_type_id, instrument_type, instrument_number } ], summary: { amount_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total } }</p>\n","urlObject":{"path":["v1","payment-register"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"820c56b5-7fdd-4073-43f0-40470ffe2247"},{"name":"Receipt register","id":"74114728-eacc-902b-c391-9d6ca7af5155","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-04-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/receipt-register","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/receipt-register</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/receipt-register</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.registers.receipt</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.registers.receipt</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally fromDate and toDate (YYYY-MM-DD; one alone means that one day), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate/toDate the whole year (one date alone = that one day); page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100); the summary covers the whole range.</p>\n<p>data: { rows: [ { date, voucher_code, voucher_type_id, voucher_number, gst_nature_id, gst_nature, mode_id, mode_name, account_id, account_name, mobile_number, amount, short_narration, instrument_type_id, instrument_type, instrument_number } ], summary: { amount_total } }</p>\n","urlObject":{"path":["v1","receipt-register"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"74114728-eacc-902b-c391-9d6ca7af5155"},{"name":"Journal register","id":"817861ab-e1eb-06b0-1997-7995aa47e654","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-04-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/journal-register","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/journal-register</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/journal-register</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.registers.journal</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.registers.journal</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally fromDate and toDate (YYYY-MM-DD; one alone means that one day), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate/toDate the whole year (one date alone = that one day); page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100); the summary covers the whole range.</p>\n<p>data: { rows: [ { date, voucher_code, voucher_type_id, voucher_number, line_srno, voucher_line_no, gst_nature_id, gst_nature, account_id, account_name, mobile_number, debit_amount, credit_amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, short_narration, instrument_type_id, instrument_type, instrument_number } ], summary: { debit_total, credit_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total } }</p>\n","urlObject":{"path":["v1","journal-register"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"817861ab-e1eb-06b0-1997-7995aa47e654"},{"name":"Contra register","id":"32682cdb-5449-e308-649a-7a789589db83","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-04-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/contra-register","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/contra-register</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/contra-register</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.registers.contra</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.registers.contra</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally fromDate and toDate (YYYY-MM-DD; one alone means that one day), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate/toDate the whole year (one date alone = that one day); page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100); the summary covers the whole range.</p>\n<p>data: { rows: [ { date, voucher_code, voucher_type_id, voucher_number, line_srno, voucher_line_no, account_id, account_name, mobile_number, debit_amount, credit_amount, short_narration, instrument_type_id, instrument_type, instrument_number } ], summary: { debit_total, credit_total } }</p>\n","urlObject":{"path":["v1","contra-register"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"32682cdb-5449-e308-649a-7a789589db83"},{"name":"Pending sales orders (item rows)","id":"f77c3ea6-21f3-df9a-8788-5acdd9b09ced","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}},\n  \"statusField\": \"OF1\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/pending-sales-orders","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/pending-sales-orders</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/pending-sales-orders</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.sales-orders.pending</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.sales-orders.pending</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), customerId (number), and optionally referenceNumber (string), statusField (OF1 to OF10), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): referenceNumber none; statusField none; page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100).</p>\n<p>data: array of { sales_order_refcode, reference_no, order_date, due_date, customer_id, customer_name, product_id, product_name, unit_id, unit_name, status_id, status, total_qty, pending_qty, product_stock }</p>\n","urlObject":{"path":["v1","pending-sales-orders"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"f77c3ea6-21f3-df9a-8788-5acdd9b09ced"},{"name":"Pending sales orders per voucher","id":"1b7e0043-0e7d-2cff-2e55-16d252ec8c42","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"customerId\": {{customerId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/pending-sales-order-vouchers","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/pending-sales-order-vouchers</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/pending-sales-order-vouchers</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>customerId</code> · operation <code>busy.sales-orders.pending-vouchers</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.sales-orders.pending-vouchers</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), customerId (number), and optionally statusField (OF1 to OF10), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): statusField none; page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100).</p>\n<p>data: array of { sales_order_refcode, sales_order_vch_code, sales_order_number, order_date, due_date, customer_id, customer_name, material_center_id, material_center_name, status_id, status, total_ordered_qty, total_dispatched_qty, total_pending_qty }</p>\n","urlObject":{"path":["v1","pending-sales-order-vouchers"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"1b7e0043-0e7d-2cff-2e55-16d252ec8c42"},{"name":"Sale invoices","id":"5e367b2f-c12e-40ec-72eb-863e32f737e3","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"startDate\": \"{{financialYear}}-04-01\",\n  \"endDate\": \"{{financialYear}}-04-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/all-sale-invoices","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/all-sale-invoices</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/all-sale-invoices</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>startDate</code>, <code>endDate</code> · operation <code>busy.sales.invoices</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.sales.invoices</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), startDate and endDate (YYYY-MM-DD), and optionally customerId, materialCenterId, materialCenterGroupId, page and pageSize (numbers).</p>\n<p>Defaults (on the PC): page 1; pageSize 100 (startDate and endDate have no default).</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100).</p>\n<p>data: array of sale invoices (vch_code, date, invoice_no, material centre and group, sale type, customer, billing, salesman, total_amount and grand_total as two-decimal strings, bill reference and payment status, transport, e-way and e-invoice numbers, last action)</p>\n","urlObject":{"path":["v1","all-sale-invoices"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"5e367b2f-c12e-40ec-72eb-863e32f737e3"},{"name":"Product lines of one sale invoice","id":"f5190bb5-982b-928a-f663-b2ee6ebe470b","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherId\": {{salesInvoiceVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sale-invoice-products","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/sale-invoice-products</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/sale-invoice-products</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>voucherId</code> · operation <code>busy.sales.invoices.products</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.sales.invoices.products</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string) and voucherId (number).</p>\n<p>data: array of every product line with GST (voucher, customer, material centre, sale type, product, group, HSN, MRP, quantity, unit, rates, taxable_value, GST/CGST/SGST/IGST percentages and amounts, total_amount)</p>\n","urlObject":{"path":["v1","sale-invoice-products"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"f5190bb5-982b-928a-f663-b2ee6ebe470b"},{"name":"Sale vouchers with their items","id":"f36611f5-0a82-6a0a-53cc-e42ace35c88a","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"fromDate\": \"{{financialYear}}-04-01\",\n  \"toDate\": \"{{financialYear}}-04-07\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/list-sale-vouchers-with-items","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/list-sale-vouchers-with-items</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/list-sale-vouchers-with-items</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.sales.vouchers-with-items</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.sales.vouchers-with-items</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), and optionally fromDate and toDate (YYYY-MM-DD; one alone means that one day), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): fromDate/toDate the whole year (one date alone = that one day); page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100); the summary covers the whole range; pages count vouchers and never split one.</p>\n<p>data: { vouchers: [ { voucher_code, voucher_number, date, …, total_quantity, total_amount, items: [ … ] } ], summary: { total_quantity, total_amount, item_row_count, voucher_count } }</p>\n","urlObject":{"path":["v1","list-sale-vouchers-with-items"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"f36611f5-0a82-6a0a-53cc-e42ace35c88a"}],"id":"9f876215-d966-4441-b726-dde947bef1ff","description":"<p>The same registers, order and invoice reads as Local, relayed to the PC. Read only. These are POST requests only because they carry a JSON body; none of them changes BUSY or AI Zeny.</p>\n","_postman_id":"9f876215-d966-4441-b726-dde947bef1ff","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ Voucher PDFs — BUSY print flag changes","item":[{"name":"⚠ busy.vouchers.pdf – Sales invoice PDF","id":"174acc28-fdce-cb1f-52af-1631d7146f5d","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"salesInvoice\",\n  \"voucherId\": {{salesInvoiceVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/voucher-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /v1/voucher-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (<code>DocPrinted</code>).</p>\n<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/voucher-pdf</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — prints an existing voucher (BUSY marks it printed)\n<strong>Path:</strong> relayed to the PC through Pusher; the PC prints with BUSY and returns the PDF as base64. Cloud route exists for all six voucher types (cloud <code>3b13ab1</code>); the current Windows build runs it. Needs the PC online; the 2 MiB result limit applies.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>voucherType</code>, exactly one of <code>voucherId</code> / <code>voucherNumber</code> · operation <code>busy.vouchers.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body as the Local request; the text below is the Local request's description.</strong></p>\n<p><strong><code>busy.vouchers.pdf</code></strong> (<code>POST /api/v1/voucher-pdf</code>). One existing BUSY voucher printed by <strong>BUSY's own printing</strong> on this PC and returned as a PDF in <code>data.contentBase64</code> (standard base64). This request prints a <strong>sales invoice</strong>; the requests below it print the other types through the same route. <strong>AI Zeny creates no accounting voucher in this request</strong>, but like printing in BUSY, BUSY marks the printed voucher as printed (its <code>DocPrinted</code> flag); nothing else in the books changes.</p>\n<p><strong><code>voucherType</code></strong> (exact, case-sensitive): <code>salesInvoice</code>, <code>salesReturn</code>, <code>receipt</code>, <code>purchaseInvoice</code>, <code>purchaseReturn</code>, <code>payment</code>. Any other value is <code>400 INVALID_PARAMETER</code> (<code>field: voucherType</code>).</p>\n<p>Request: <code>{ companyCode, financialYear, voucherType, voucherId | voucherNumber, formatName? }</code></p>\n<ul>\n<li>Exactly one of <code>voucherId</code> (BUSY's voucher code, 1–2147483647) and <code>voucherNumber</code> (as BUSY shows it, 1–50 characters, matched exactly including case). The voucher is looked up <strong>only among vouchers of that type</strong>: a sales return and a sales invoice can share a number (<code>1/2026-27</code> on COMP0002); another type's code is <code>404</code>.</li>\n<li><code>formatName</code>: one of the company's BUSY print formats <strong>for that voucher type</strong>, exactly as named (<code>STANDARD</code>, not <code>Standard</code>). Left out = BUSY's default for the type (<code>STANDARD</code>); if the company has no STANDARD format for the type, <code>409 BUSY_PRINT_FORMAT_MISSING</code> and nothing is printed (BUSY would create the format while printing).</li>\n</ul>\n<p>Response (200): <code>data</code> = <code>{ fileName, mimeType, byteLength, sha256, pages, contentBase64 }</code>; <code>fileName</code> starts with the type (<code>SalesInvoice-</code>, <code>SalesReturn-</code>, <code>Receipt-</code>, <code>PurchaseInvoice-</code>, <code>PurchaseReturn-</code>, <code>Payment-</code>). <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, voucherType, lookup, voucherId, voucherNumber, voucherDate, formatSource (busyDefault | selected), formatName, elapsedMs, executedAt</code>.</p>\n<p>Errors: <code>400 INVALID_PARAMETER</code> / <code>BAD_REQUEST</code>; <code>404 NOT_FOUND</code> (<code>field</code> voucherId, voucherNumber or formatName — the message lists the type's formats); <code>409 BUSY_PRINT_FORMAT_MISSING</code>; <code>422 BUSY_DATA_INCONSISTENT</code> (several vouchers of the type share the number: send voucherId), <code>RESULT_TOO_LARGE</code> (over 1 MiB), <code>BUSY_COM_PDF_BLANK</code>; <code>409 BUSY_COM_SIGN_IN_UNSUPPORTED</code>; <code>502 BUSY_COM_*</code> print failures; <code>503</code> PC prerequisites (<code>BUSY_COM_DEFAULT_PRINTER_MISSING</code> …) and <code>BUSY_COM_QUEUE_TIMEOUT</code>; <code>504 BUSY_COM_TIMEOUT</code>. One PDF at a time, up to 2 minutes each: give the request a long timeout.</p>\n<p>Cloud: all six types are also relayed through <code>{{cloudBaseUrl}}/v1/voucher-pdf</code> (cloud <code>3b13ab1</code>; see Cloud Relay → Voucher PDFs), and the current Windows build runs them.</p>\n<p><em>Saved examples for this request are in the Local PC folder (Local PC → Voucher PDFs → Sales invoice PDF).</em></p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5aa.</p>\n","urlObject":{"path":["v1","voucher-pdf"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"174acc28-fdce-cb1f-52af-1631d7146f5d"},{"name":"⚠ busy.vouchers.pdf – Sales return PDF","id":"a61dc61c-5c31-8585-b84c-28eddb591367","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"salesReturn\",\n  \"voucherNumber\": \"{{salesReturnNumber}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/voucher-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /v1/voucher-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (<code>DocPrinted</code>).</p>\n<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/voucher-pdf</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — prints an existing voucher (BUSY marks it printed)\n<strong>Path:</strong> relayed to the PC through Pusher; the PC prints with BUSY and returns the PDF as base64. Cloud route exists for all six voucher types (cloud <code>3b13ab1</code>); the current Windows build runs it. Needs the PC online; the 2 MiB result limit applies.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>voucherType</code>, exactly one of <code>voucherId</code> / <code>voucherNumber</code> · operation <code>busy.vouchers.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body as the Local request; the text below is the Local request's description.</strong></p>\n<p><strong><code>busy.vouchers.pdf</code></strong> with <code>voucherType: \"salesReturn\"</code> — one BUSY <strong>sales return</strong> (BUSY voucher type 3), printed by BUSY as a <strong>Credit Note</strong>, returned as a base64 PDF. Same route, rules, answer and errors as <strong>busy.vouchers.pdf – Sales invoice PDF</strong> (read that request's description); only the type differs.</p>\n<ul>\n<li>Looked up <strong>by number among sales returns only</strong>: on the test company COMP0002 the number <code>1/2026-27</code> is both a sale and a sales return, and this request finds the sales return (<code>salesReturnVoucherId</code> 27).</li>\n<li><code>formatName</code>: one of the company's <strong>sales-return</strong> formats (BUSY <code>PrinterReps</code> RepID 9), e.g. <code>STANDARD</code>; a sales-invoice format is refused with <code>404</code> (<code>field: formatName</code>).</li>\n<li><code>fileName</code> starts with <code>SalesReturn-</code>. BUSY marks the printed voucher as printed, as when printing from BUSY.</li>\n<li>Also through the cloud: <code>{{cloudBaseUrl}}/v1/voucher-pdf</code> relays this type (cloud <code>3b13ab1</code>; see Cloud → Voucher PDFs).</li>\n</ul>\n<p><em>Saved examples: \"200 – sales return PDF (synthetic example)\" has a wrong byteLength/sha256 for its made-up base64; delete it in Postman and keep \"200 – sales return PDF (synthetic)\".</em></p>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5aa.</p>\n","urlObject":{"path":["v1","voucher-pdf"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"a61dc61c-5c31-8585-b84c-28eddb591367"},{"name":"⚠ busy.vouchers.pdf – Receipt PDF","id":"e9a581a5-30ed-f6a6-ad77-6b08113327b0","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"receipt\",\n  \"voucherId\": {{receiptVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/voucher-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /v1/voucher-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (<code>DocPrinted</code>).</p>\n<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/voucher-pdf</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — prints an existing voucher (BUSY marks it printed)\n<strong>Path:</strong> relayed to the PC through Pusher; the PC prints with BUSY and returns the PDF as base64. Cloud route exists for all six voucher types (cloud <code>3b13ab1</code>); the current Windows build runs it. Needs the PC online; the 2 MiB result limit applies.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>voucherType</code>, exactly one of <code>voucherId</code> / <code>voucherNumber</code> · operation <code>busy.vouchers.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body as the Local request; the text below is the Local request's description.</strong></p>\n<p><strong><code>busy.vouchers.pdf</code></strong> with <code>voucherType: \"receipt\"</code> — one BUSY <strong>receipt</strong> (BUSY voucher type 14), printed by BUSY as a <strong>Receipt</strong> (party, amount, amount in words), returned as a base64 PDF. Same route, rules, answer and errors as <strong>busy.vouchers.pdf – Sales invoice PDF</strong> (read that request's description); only the type differs.</p>\n<ul>\n<li>Looked up <strong>by voucher code among receipts only</strong> (<code>receiptVoucherId</code>, COMP0002 voucher 3, number <code>1</code>; a debit note there also has number <code>1</code>, and a sale's code is <code>404</code> here).</li>\n<li><code>formatName</code>: one of the company's <strong>receipt</strong> formats (BUSY <code>PrinterReps</code> RepID 3), e.g. <code>STANDARD</code>. Without it, BUSY prints its STANDARD receipt; a company with no STANDARD receipt format answers <code>409 BUSY_PRINT_FORMAT_MISSING</code>.</li>\n<li><code>fileName</code> starts with <code>Receipt-</code>; a receipt PDF is about 24 KB. BUSY marks the printed receipt as printed, as when printing from BUSY.</li>\n<li>Also through the cloud: <code>{{cloudBaseUrl}}/v1/voucher-pdf</code> relays this type (cloud <code>3b13ab1</code>; see Cloud → Voucher PDFs).</li>\n</ul>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5aa.</p>\n","urlObject":{"path":["v1","voucher-pdf"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"e9a581a5-30ed-f6a6-ad77-6b08113327b0"},{"name":"⚠ busy.vouchers.pdf – Purchase invoice PDF","id":"4a925660-4148-cac2-bedb-2532c5c5f574","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"purchaseInvoice\",\n  \"voucherNumber\": \"{{purchaseInvoiceNumber}}\",\n  \"formatName\": \"{{voucherPdfFormat}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/voucher-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /v1/voucher-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (<code>DocPrinted</code>).</p>\n<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/voucher-pdf</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — prints an existing voucher (BUSY marks it printed)\n<strong>Path:</strong> relayed to the PC through Pusher; the PC prints with BUSY and returns the PDF as base64. Cloud route exists for all six voucher types (cloud <code>3b13ab1</code>); the current Windows build runs it. Needs the PC online; the 2 MiB result limit applies.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>voucherType</code>, exactly one of <code>voucherId</code> / <code>voucherNumber</code> · operation <code>busy.vouchers.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body as the Local request; the text below is the Local request's description.</strong></p>\n<p><strong><code>busy.vouchers.pdf</code></strong> with <code>voucherType: \"purchaseInvoice\"</code> — one BUSY <strong>purchase</strong> voucher (BUSY voucher type 2), printed by BUSY as a <strong>Tax Invoice</strong> with the supplier's details, returned as a base64 PDF. Same route, rules, answer and errors as <strong>busy.vouchers.pdf – Sales invoice PDF</strong> (read that request's description); only the type differs.</p>\n<ul>\n<li>Looked up <strong>by number among purchases only</strong> (<code>purchaseInvoiceNumber</code>, COMP0002 voucher 10, number <code>Q123</code>), with a <strong>named format</strong> (<code>voucherPdfFormat</code> = <code>STANDARD</code>).</li>\n<li><code>formatName</code>: one of the company's <strong>purchase-invoice</strong> formats (BUSY <code>PrinterReps</code> RepID 2). A format of another voucher type is refused with <code>404</code> (<code>field: formatName</code>) — BUSY itself would quietly print its default instead.</li>\n<li><code>fileName</code> starts with <code>PurchaseInvoice-</code>. BUSY marks the printed voucher as printed, as when printing from BUSY.</li>\n<li>Also through the cloud: <code>{{cloudBaseUrl}}/v1/voucher-pdf</code> relays this type (cloud <code>3b13ab1</code>; see Cloud → Voucher PDFs).</li>\n</ul>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5aa.</p>\n","urlObject":{"path":["v1","voucher-pdf"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"4a925660-4148-cac2-bedb-2532c5c5f574"},{"name":"⚠ busy.vouchers.pdf – Purchase return PDF","id":"3b697d64-4d41-83f3-5cde-40fa27897cd5","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"purchaseReturn\",\n  \"voucherId\": {{purchaseReturnVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/voucher-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /v1/voucher-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (<code>DocPrinted</code>).</p>\n<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/voucher-pdf</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — prints an existing voucher (BUSY marks it printed)\n<strong>Path:</strong> relayed to the PC through Pusher; the PC prints with BUSY and returns the PDF as base64. Cloud route exists for all six voucher types (cloud <code>3b13ab1</code>); the current Windows build runs it. Needs the PC online; the 2 MiB result limit applies.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>voucherType</code>, exactly one of <code>voucherId</code> / <code>voucherNumber</code> · operation <code>busy.vouchers.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body as the Local request; the text below is the Local request's description.</strong></p>\n<p><strong><code>busy.vouchers.pdf</code></strong> with <code>voucherType: \"purchaseReturn\"</code> — one BUSY <strong>purchase return</strong> (BUSY voucher type 10), printed by BUSY as a <strong>Debit Note</strong>, returned as a base64 PDF. Same route, rules, answer and errors as <strong>busy.vouchers.pdf – Sales invoice PDF</strong> (read that request's description); only the type differs.</p>\n<ul>\n<li>Looked up <strong>by voucher code among purchase returns only</strong> (<code>purchaseReturnVoucherId</code>, COMP0002 voucher 29, number <code>12</code>). A BUSY <em>debit note</em> voucher (type 17) is a different type and is not printed here.</li>\n<li><code>formatName</code>: one of the company's <strong>purchase-return</strong> formats (BUSY <code>PrinterReps</code> RepID 10), e.g. <code>STANDARD</code>.</li>\n<li><code>fileName</code> starts with <code>PurchaseReturn-</code>. BUSY marks the printed voucher as printed, as when printing from BUSY.</li>\n<li>Also through the cloud: <code>{{cloudBaseUrl}}/v1/voucher-pdf</code> relays this type (cloud <code>3b13ab1</code>; see Cloud → Voucher PDFs).</li>\n</ul>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5aa.</p>\n","urlObject":{"path":["v1","voucher-pdf"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"3b697d64-4d41-83f3-5cde-40fa27897cd5"},{"name":"⚠ busy.vouchers.pdf – Payment PDF","id":"8145046f-5f25-4ce2-8690-7f6f48e9f338","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"voucherType\": \"payment\",\n  \"voucherId\": {{paymentVoucherId}}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/voucher-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /v1/voucher-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. BUSY marks a voucher printed (<code>DocPrinted</code>).</p>\n<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/voucher-pdf</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — prints an existing voucher (BUSY marks it printed)\n<strong>Path:</strong> relayed to the PC through Pusher; the PC prints with BUSY and returns the PDF as base64. Cloud route exists for all six voucher types (cloud <code>3b13ab1</code>); the current Windows build runs it. Needs the PC online; the 2 MiB result limit applies.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>voucherType</code>, exactly one of <code>voucherId</code> / <code>voucherNumber</code> · operation <code>busy.vouchers.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body as the Local request; the text below is the Local request's description.</strong></p>\n<p><strong><code>busy.vouchers.pdf</code></strong> with <code>voucherType: \"payment\"</code> — one BUSY <strong>payment</strong> (BUSY voucher type 19), printed by BUSY as a <strong>Payment Advice</strong> (party, amount, amount in words), returned as a base64 PDF. Same route, rules, answer and errors as <strong>busy.vouchers.pdf – Sales invoice PDF</strong> (read that request's description); only the type differs.</p>\n<ul>\n<li>Looked up <strong>by voucher code among payments only</strong> (<code>paymentVoucherId</code>, COMP0002 voucher 22, number <code>P09</code>).</li>\n<li><code>formatName</code>: one of the company's <strong>payment</strong> formats (BUSY <code>PrinterReps</code> RepID 12), e.g. <code>STANDARD</code>.</li>\n<li><code>fileName</code> starts with <code>Payment-</code>; a payment PDF is about 25 KB. BUSY marks the printed voucher as printed, as when printing from BUSY.</li>\n<li>Also through the cloud: <code>{{cloudBaseUrl}}/v1/voucher-pdf</code> relays this type (cloud <code>3b13ab1</code>; see Cloud → Voucher PDFs).</li>\n</ul>\n<p>Canonical contract: <code>docs/LOCAL-API.md</code> section 5aa.</p>\n","urlObject":{"path":["v1","voucher-pdf"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"8145046f-5f25-4ce2-8690-7f6f48e9f338"}],"id":"f959ffc6-2dce-4b5d-90b6-52c706590dde","description":"<p>Relayed voucher printing executes on the PC through BUSY and marks the voucher printed (DocPrinted). Explicit one-send confirmation is required on each request; cloud availability follows its separately deployed route.</p>\n","_postman_id":"f959ffc6-2dce-4b5d-90b6-52c706590dde","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Custom SQL, Named Reports & Scripts (read only)","item":[{"name":"Execute one read-only SELECT","id":"f4f43f15-b200-45a0-8d4c-576e9f60c06a","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"query\": \"SELECT Code, Name FROM Master1 WHERE MasterType = @type ORDER BY Code\",\n  \"parameters\": {\n    \"type\": 2\n  },\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/execute-custom-sql","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/execute-custom-sql</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/execute-custom-sql</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>query</code> · operation <code>busy.custom-sql.execute</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.custom-sql.execute</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), query (string: one read-only SELECT in the company's provider SQL), and optionally parameters (object of scalar values bound to <code>@name</code> placeholders), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): parameters none; page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100), page × pageSize ≤ 100000; no total count.</p>\n<p>The PC's read-only boundary refuses anything but one SELECT (writes, DDL, execution, system objects, comments, second statements) and runs it read only; a refused query is answered with its V1 code and never reaches BUSY.</p>\n<p>data: { columns: [ { name, type } ], rows: [ [ cell, … ] ] } (positional rows)</p>\n","urlObject":{"path":["v1","execute-custom-sql"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"f4f43f15-b200-45a0-8d4c-576e9f60c06a"},{"name":"Run a named report from the local registry","id":"fbb929a4-0c53-a47e-cebd-3618de5f82e2","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"queryName\": \"stock_status_with_mc_name\",\n  \"parameters\": {\n    \"branchId\": 0\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/execute-custom-query","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/execute-custom-query</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs the same operation as Local <code>POST /api/v1/execute-custom-query</code> and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>queryName</code> · operation <code>busy.custom-query.execute</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p>Signed command <code>busy.custom-query.execute</code>.</p>\n<p>Body: companyCode (string), financialYear (four-digit string), queryName (string: a built-in report — <code>stock_aging_fifo</code>, or <code>stock_status_with_mc_name</code> and its aliases — or the name of a saved query on the PC), and optionally parameters (object: branchId, asOnDate), page and pageSize (numbers).</p>\n<p>Defaults (on the PC): parameters none (branchId none = every material centre; asOnDate today UTC on the PC); page 1; pageSize 100.</p>\n<p>Paging: page ≥ 1 (default 1), pageSize 1–500 (default 100).</p>\n<p>A name that is neither is <code>404</code>.</p>\n<p><strong>Saved custom queries too</strong> (cloud <code>3b13ab1</code>): any <code>queryName</code> that is not a built-in report is one of the customer's saved queries on the PC — trimmed, each whitespace run becomes <code>-</code>, then <code>^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$</code> (a name breaking that rule is <code>400</code> from the cloud). The PC runs the company's provider definition (<code>metadata.querySource</code> <code>builtIn</code> | <code>saved</code>); a well-formed name the PC does not hold is <code>404</code> from the PC, and <code>409 SAVED_QUERY_PROVIDER_MISSING</code> / <code>SAVED_QUERY_INVALID</code> as on the Local API. Saved queries are created and changed only on the PC (Local API).</p>\n<p>data: { columns: [ { name, type } ], rows: [ [ cell, … ] ] }</p>\n","urlObject":{"path":["v1","execute-custom-query"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"fbb929a4-0c53-a47e-cebd-3618de5f82e2"},{"name":"Run a named script","id":"a529f108-fc6e-0161-aed5-8b78ba14b882","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"scriptName\": \"{{scriptName}}\",\n  \"parameters\": { \"minAmount\": 1000 }\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/execute-script","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/execute-script</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only towards BUSY (the script reads through the PC's operations)\n<strong>Path:</strong> relayed to the PC through Pusher; the PC runs the saved named script with every Local check and limit. Cloud route exists (cloud <code>3b13ab1</code>); the current Windows build executes it.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>scriptName</code> · operation <code>busy.script.execute</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body as the Local request; the text below is the Local request's description.</strong></p>\n<p>Runs the named script <code>{{scriptName}}</code> (enabled, assigned to the company). <code>parameters</code> is handed to the script as <code>input.parameters</code>, numbers exact. Answer: <code>data</code> = what the script returns (an object or array); <code>metadata = { apiVersion, operation: busy.script.execute, requestId, companyCode, financialYear, script { name, revision }, calls, httpRequests, elapsedMs, executedAt }</code>.</p>\n<p>Errors: <code>404 SCRIPT_NOT_FOUND</code>, <code>409 SCRIPT_NOT_ASSIGNED</code> / <code>SCRIPT_DISABLED</code> (field <code>scriptName</code>), <code>422 SCRIPT_FAILED</code> (message with the script line), <code>SCRIPT_OUTPUT_INVALID</code>, <code>SCRIPT_OUTPUT_TOO_LARGE</code>, <code>SCRIPT_LIMIT_EXCEEDED</code>, <code>SCRIPT_RECURSION</code>, <code>403 SCRIPT_SCOPE_DENIED</code>, <code>504 SCRIPT_TIMEOUT</code>, and the company and year refusals.</p>\n<p>Also through the cloud: <code>{{cloudBaseUrl}}/v1/execute-script</code> (cloud <code>3b13ab1</code>; see Cloud → Custom SQL, Named Reports &amp; Scripts), with the same checks and limits on the PC. The cloud sends it to the PC once and never retries it; send an <code>Idempotency-Key</code> header to have a repeat refused (<code>409</code>) instead of run again.</p>\n","urlObject":{"path":["v1","execute-script"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"a529f108-fc6e-0161-aed5-8b78ba14b882"},{"name":"Standard API with a transform variant","id":"643c4ecb-1b9a-e465-5cf0-41ea249fb18f","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"script\": \"{{scriptName}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/material-centers","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/material-centers</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> relayed to the PC through Pusher; the PC runs the operation, then applies the named transform script assigned to this company and route. Cloud <code>3b13ab1</code> accepts the <code>script</code> member on every synchronous BUSY route except the credit-line stream, <code>/execute-script</code>, <code>/voucher-pdf</code> and the writes. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code> · operation <code>busy.material-centers.list</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body as the Local request; the text below is the Local request's description.</strong></p>\n<p>Any synchronous V1 route (not the stream, not execute-script) accepts one extra member, <code>\"script\": \"&lt;name&gt;\"</code>: the response-transform variant (or default) assigned to this company and route. The operation runs first; its failure is the answer and no script runs. Then the named script transforms <code>data</code>; <code>metadata</code> stays the operation's own plus <code>metadata.script { name, revision, selectedBy: \"request\", calls, httpRequests, elapsedMs }</code>. An unknown, disabled or unassigned name is <code>404 SCRIPT_NOT_FOUND</code> / <code>409 SCRIPT_DISABLED</code> / <code>409 SCRIPT_NOT_ASSIGNED</code> (field <code>script</code>) — never another script or the untransformed data. Without <code>script</code>, the company's enabled default (if any) applies.</p>\n<p>The same member works on any other synchronous Cloud BUSY route, for example <code>POST {{cloudBaseUrl}}/v1/customers</code> with <code>\"script\": \"Customer-Summary\"</code>.</p>\n","urlObject":{"path":["v1","material-centers"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"643c4ecb-1b9a-e465-5cf0-41ea249fb18f"},{"name":"Run a saved query by name","id":"9a371ade-2539-d305-fe0d-a688122a75f3","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"queryName\": \"{{savedQueryName}}\",\n  \"parameters\": { \"fromCode\": 1 },\n  \"page\": 1,\n  \"pageSize\": 100\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/execute-custom-query","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/execute-custom-query</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — does not write to BUSY\n<strong>Path:</strong> the cloud signs the call and delivers it to the enrolled PC through Pusher; the PC runs its saved query and posts the result back. Needs the PC online; 60 calls/min per token; results over 2 MiB are refused.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>queryName</code> · operation <code>busy.custom-query.execute</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body as the Local request; the text below is the Local request's description.</strong></p>\n<p>Runs the saved query <code>{{savedQueryName}}</code> (built-in report names are looked up first and answer as before). <code>parameters</code> holds one value per declared parameter of its declared type; a required one must be present and not null; an optional one that is missing binds NULL.</p>\n<p>Answer: <code>data: { columns: [ { name, type } ], rows: [ [ … ] ] }</code> (positional, repeated names kept, NULLs, exact decimals and 64-bit integers); <code>metadata</code> as <code>execute-custom-query</code> with <code>querySource: \"saved\"</code>.</p>\n<p>Errors: <code>400 INVALID_PARAMETER</code> (field <code>parameters</code>), <code>404 NOT_FOUND</code> (field <code>queryName</code>), <code>409 SAVED_QUERY_PROVIDER_MISSING</code>, <code>409 SAVED_QUERY_INVALID</code>, <code>422 CUSTOM_SQL_FAILED</code> / <code>RESULT_TOO_LARGE</code> / <code>UNSUPPORTED_VALUE</code>, and the company and year refusals.</p>\n<p>Through the cloud (cloud <code>3b13ab1</code>) the name must also pass the cloud's rule: trimmed, each whitespace run becomes <code>-</code> (\"Top Debtors\" is sent as <code>Top-Debtors</code>), then <code>^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$</code>; a name breaking it is <code>400</code> from the cloud, and a well-formed name the PC does not hold is the PC's <code>404 NOT_FOUND</code> (field <code>queryName</code>). Saved queries are created and changed only on the PC (Local API).</p>\n<p><strong>Test scenarios:</strong> This normal saved-query request requires HTTP 200, <code>success: true</code>, result columns/rows and <code>querySource: saved</code>. To test a documented refusal deliberately, set the current variable <code>expectedSavedQueryErrorCode</code> to the exact expected error code for that separate scenario; the test then requires a 4xx/5xx envelope with that exact code. Clear it for the normal success case. No request is sent by this change.</p>\n","urlObject":{"path":["v1","execute-custom-query"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"9a371ade-2539-d305-fe0d-a688122a75f3"}],"id":"65a514b2-7ccc-459d-bf24-7c2516882bbe","description":"<p>Your own read-only SQL, the built-in named reports and running a saved named script (<code>/execute-script</code>), relayed to the PC; the current Windows build runs all three. Creating or changing saved queries and scripts is local only (no cloud route). These are POST requests only because they carry a JSON body; none of them changes BUSY or AI Zeny.</p>\n","_postman_id":"65a514b2-7ccc-459d-bf24-7c2516882bbe","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ Master Create & Modify — WRITES TO BUSY","item":[{"name":"⚠ BUSY master – create account (writes to BUSY)","id":"1d03cecf-2228-48b9-98c9-ff96b8bf3416","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Account 01\",\n  \"alias\": \"AZAPI-ACC-01\",\n  \"parentGroup\": { \"name\": \"Sundry Debtors\" },\n  \"address\": {\n    \"line1\": \"1 Example Road\",\n    \"state\": { \"name\": \"Delhi\" },\n    \"pinCode\": \"110001\",\n    \"mobile\": \"9000000000\",\n    \"email\": \"accounts@example.invalid\"\n  },\n  \"gstRegistrationType\": \"unregistered\",\n  \"creditDays\": 15,\n  \"creditLimit\": 25000\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/account-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/account-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)\n<strong>Status (2026-10-13):</strong> the cloud route is live. Windows relays master writes from source commit <code>6e3f9aa</code> onward (same organization token as the reads; installed on the development PC as candidate <code>586f094</code> and live-tested through the cloud on COMP0002 on 2026-10-13; not released): the BUSY job starts only if it can finish within the command's 400 s, else <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing written; the only write error you may resend); once BUSY is saving it is never stopped; refusals carry <code>metadata.error.details</code>. A PC running an earlier build — every released version up to 0.0.11 — answers <code>502 DEVICE_ERROR</code> (<code>REPORT_UNSUPPORTED</code>) and writes nothing. The cloud publishes a write once, never retries it, and answers <code>504 WRITE_RESULT_UNKNOWN</code> when the PC's result does not arrive in time: look the master up before trying again.\n<strong>Required:</strong> see the Local request · operation <code>busy.accounts.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body as the Local request; the text below is the Local request's description.</strong></p>\n<p><strong>Mutating — writes to the BUSY books. Run manually, one at a time.</strong> <code>busy.accounts.create</code> (<code>POST /api/v1/account-create</code>) creates one BUSY account (ledger) through BUSY's own COM component on this PC, then reads it back from BUSY and checks every field you sent before answering. <strong>SQL Server companies with a SQL login, and Access companies</strong> (the PC decides: Windows <code>6c5776d</code> or later accepts Access; an earlier PC answers Access with <code>409 MASTER_WRITE_PROVIDER_UNSUPPORTED</code>). Never an upsert. For Cloud Relay, a compatible Windows agent is required; an older agent may refuse without writing. See Cloud Relay → ⚠ Master Create &amp; Modify. Never run this write from scripts.</p>\n<p><strong>Safe test guidance</strong></p>\n<ul>\n<li>Use only a <strong>development-test company</strong> (<code>targetCompanyCode</code>, e.g. COMP0002 on the development PC) and a <strong>new, unique test name</strong> (change <code>name</code> and <code>alias</code> before each send). Never a customer's company.</li>\n<li>Nothing is deleted automatically: a created test account stays in BUSY. Remove it in BUSY yourself if needed.</li>\n<li><strong>Never retry a write blindly.</strong> A second send of the same body is refused (<code>409 MASTER_NAME_TAKEN</code>) if the first saved. After <code>504 BUSY_WRITE_UNCERTAIN</code>, read <code>metadata.error.details.reconciliation</code> (<code>found</code> + <code>masterId</code>, <code>notFound</code>, <code>notChecked</code>) and look the account up (Customers) before anything else.</li>\n<li><code>502 BUSY_WRITE_UNVERIFIED</code> means BUSY <strong>did</strong> save but its read-back differs (<code>details.masterId</code>, <code>details.mismatchedFields</code>): check it in BUSY.</li>\n<li>One BUSY job at a time on the PC (shared with voucher PDFs), up to 2 minutes: give the request a long timeout.</li>\n</ul>\n<p><strong>Body:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>name</code> (1-40, required), <code>alias</code>, <code>printName</code> (1-60), <code>parentGroup</code> (required, <code>{\"code\": n}</code> or <code>{\"name\": \"…\"}</code>), <code>address</code> {<code>line1</code>…<code>line4</code>, <code>state</code>, <code>pinCode</code>, <code>station</code>, <code>contactPerson</code>, <code>telephone</code>, <code>mobile</code>, <code>whatsApp</code>, <code>email</code>, <code>gstin</code>, <code>pan</code>}, <code>gstRegistrationType</code> (<code>registered</code> | <code>unregistered</code>), <code>creditDays</code> (0-9999), <code>creditLimit</code> (&gt; 0), <code>openingBalance</code>.</p>\n<p><strong>Opening balance</strong> (part of the books, optional): <code>{ \"amount\": 300, \"type\": \"debit\"|\"credit\", \"allocation\": \"billWise\"|\"unallocated\", \"billReferences\": [ { \"number\": \"OB-0001\", \"date\": \"2026-03-15\", \"dueDate\": \"2026-04-15\", \"amount\": 300, \"type\": \"debit\" } ] }</code>. <code>allocation</code> is required: <code>billWise</code> needs bill references whose signed total equals the balance (dates on or before 1 April of the year, at most 50); <code>unallocated</code> allows none and says so in <code>metadata.openingBalanceAllocation</code>. The example body leaves it out on purpose.</p>\n<p><strong>Answer (200):</strong> <code>data</code> = <code>{ masterId, name, alias, fields }</code> (each field sent, as BUSY stored it; references with the code BUSY resolved); <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, masterType, outcome (created), verifiedFields, [openingBalanceAllocation], elapsedMs, executedAt</code>. The test stores <code>masterAccountId</code> / <code>masterAccountName</code> for the modify request.</p>\n<p><strong>Errors:</strong> 400 <code>BAD_REQUEST</code>, <code>INVALID_PARAMETER</code> (<code>field</code>); 404 <code>COMPANY_NOT_CONFIGURED</code>; 409 <code>MASTER_NAME_TAKEN</code>, <code>MASTER_WRITE_PROVIDER_UNSUPPORTED</code>, <code>COMPANY_DISABLED</code>, <code>FINANCIAL_YEAR_NOT_ALLOWED</code>; 422 <code>MASTER_REFERENCE_NOT_FOUND</code>, <code>MASTER_REFERENCE_AMBIGUOUS</code>; 502 <code>BUSY_WRITE_FAILED</code>, <code>BUSY_WRITE_UNVERIFIED</code>; 503 <code>BUSY_COM_*</code> prerequisites, <code>BUSY_COM_QUEUE_TIMEOUT</code>; 504 <code>BUSY_WRITE_UNCERTAIN</code>, <code>BUSY_COM_TIMEOUT</code>.</p>\n<p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5ab; customer guide <code>docs/public/api/account-and-product-masters.md</code>.</p>\n<hr />\n<p><strong>Optional fields (<code>optionalFields</code>; needs a PC build with Windows <code>a20701b</code>).</strong> Optional member keyed by slot <code>OF1</code>-<code>OF10</code> exactly as \"Optional-field definitions\" (Cloud Relay → Master Reads) lists them for the same company and year. Account fields may be text (a string, 1-255 Latin-1 characters without surrounding spaces), dropdown (an existing value), whole number, date or Yes/No, on Access companies and on SQL Server companies with a SQL login (Windows <code>3aa08bf</code>, 29 October 2026); number fields with decimals and other kinds are <code>422 OPTIONAL_FIELD_UNSUPPORTED</code>, and a PC build from before that change also refuses the non-text account kinds on SQL Server that way. A create cannot clear a slot (<code>null</code> is refused: <code>400 INVALID_PARAMETER</code>, field <code>optionalFields.OFn</code>); an empty string is refused. The PC checks every value against that year's definition; the cloud forwards the object exactly as sent.</p>\n<p>Add to the body, for example: <code>\"optionalFields\": { \"OF1\": \"Synthetic North\" }</code></p>\n<p>A master write never creates a dropdown value: an unknown one is <code>422 OPTIONAL_FIELD_VALUE_NOT_FOUND</code> (nothing written) — add it first with \"⚠ BUSY account dropdown value – create\" (or, for a product, \"⚠ BUSY product dropdown value – create\"). Other refusals: <code>422 OPTIONAL_FIELD_NOT_DEFINED</code> (field <code>optionalFields.OFn</code>), <code>422 OPTIONAL_FIELD_UNSUPPORTED</code>, <code>409 OPTIONAL_FIELD_VALUE_CHANGED</code> — each means nothing was written. On success <code>data.fields.optionalFields</code> echoes each written slot (a dropdown as <code>{ code, name }</code>, a cleared slot as <code>null</code>) and <code>metadata.verifiedFields</code> lists <code>optionalFields.OFn</code>. <code>502 BUSY_WRITE_UNVERIFIED</code> may name a slot in <code>details.mismatchedFields</code>. An earlier PC build refuses the member (<code>400 BAD_REQUEST</code>) and writes nothing. This request's saved body does not send <code>optionalFields</code> (its tests compare the fields sent); add the member when you need it.</p>\n<p><strong>Durable queue:</strong> optional strict <code>queue</code> (omitted or <code>false</code>: synchronous; <code>true</code>: a <code>202</code> job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.</p>\n<hr />\n<p><strong>Parity update (2026-10-23, deployed in release <code>790395a</code>; the PC must be Windows <code>6c5776d</code> or later for these members).</strong> This request's body sends only the basic members. New optional members and codes:</p>\n<ul>\n<li><code>queue</code> (optional, <code>true</code> or <code>false</code>, default <code>false</code>; <code>null</code> is refused <code>400</code>): with <code>true</code> the PC accepts the write on its durable queue and the answer is <strong><code>202</code></strong> with <code>data: null</code> and <code>metadata.queued: true</code>, <code>metadata.jobId</code> (32 hex), <code>metadata.status</code> — acceptance, <strong>not</strong> a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable <code>companyCode</code>/four-digit <code>financialYear</code>; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (<code>202</code>) and fails there. The cloud sends it once.</li>\n<li><code>409 OPTIONAL_FIELD_CONFIGURATION_CHANGED</code>: the year's optional-field configuration changed while the write was prepared; read the definitions again, nothing was written. Account optional fields may be text, dropdown, whole number, date or Yes/No on Access and on SQL Server with a SQL login.</li>\n<li>Shared refusals of every write, answered before anything is written: <code>403 PLAN_FEATURE_NOT_INCLUDED</code>, <code>409 PLAN_NOT_KNOWN</code>, <code>503 BUSY_COM_RECOVERY_REQUIRED</code>, <code>409 BUSY_WRITE_TARGET_CHANGED</code>, <code>422 BUSY_SETTING_REQUIRED</code>, <code>502 BUSY_SETTINGS_UNREADABLE</code>; queue refusals <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>, <code>503 WRITE_QUEUE_UNAVAILABLE</code>.</li>\n<li><code>409 MASTER_REFERENCE_CHANGED</code> (PC from Windows <code>53b556f</code>): a group, unit or tax category the request names changed in BUSY just before the save; nothing was written. Read the references again. Not retryable.</li>\n</ul>\n<p>Scenario requests for the new members are in this folder, named <code>⚠ Scenario – …</code> and <code>⚠ EXPECTED REFUSAL …</code>; they are guarded like this one (<code>confirmMutating</code> = <code>yes</code>, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","account-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"1d03cecf-2228-48b9-98c9-ff96b8bf3416"},{"name":"⚠ BUSY master – modify account (writes to BUSY)","id":"821903fd-4576-9426-b89d-7594e054a366","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"accountId\": {{masterAccountId}},\n  \"expectedName\": \"{{masterAccountName}}\",\n  \"address\": {\n    \"mobile\": \"9000000001\"\n  },\n  \"creditLimit\": 30000\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/account-modify","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/account-modify</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)\n<strong>Status (2026-10-13):</strong> the cloud route is live. Windows relays master writes from source commit <code>6e3f9aa</code> onward (same organization token as the reads; installed on the development PC as candidate <code>586f094</code> and live-tested through the cloud on COMP0002 on 2026-10-13; not released): the BUSY job starts only if it can finish within the command's 400 s, else <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing written; the only write error you may resend); once BUSY is saving it is never stopped; refusals carry <code>metadata.error.details</code>. A PC running an earlier build — every released version up to 0.0.11 — answers <code>502 DEVICE_ERROR</code> (<code>REPORT_UNSUPPORTED</code>) and writes nothing. The cloud publishes a write once, never retries it, and answers <code>504 WRITE_RESULT_UNKNOWN</code> when the PC's result does not arrive in time: look the master up before trying again.\n<strong>Required:</strong> see the Local request · operation <code>busy.accounts.modify</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body as the Local request; the text below is the Local request's description.</strong></p>\n<p><strong>Mutating — writes to the BUSY books. Run manually, one at a time.</strong> <code>busy.accounts.modify</code> (<code>POST /api/v1/account-modify</code>) changes only the fields you send of one existing BUSY account, named by BUSY's code (<code>accountId</code> = <code>customer_id</code> in the customer operations). BUSY's own record is read, edited and saved; every other field stays as it is, and the record is compared before and after (an unrequested change is reported as <code>BUSY_WRITE_UNVERIFIED</code>). SQL Server companies with a SQL login, and Access companies (Windows <code>6c5776d</code> or later; an earlier PC answers Access with <code>409 MASTER_WRITE_PROVIDER_UNSUPPORTED</code>). For Cloud Relay, a compatible Windows agent is required; an older agent may refuse without writing. See Cloud Relay → ⚠ Master Create &amp; Modify. Never run this write from scripts.</p>\n<p><strong>Safe test guidance</strong></p>\n<ul>\n<li>Change <strong>only a test account you created yourself</strong> — the create request stores <code>masterAccountId</code> and <code>masterAccountName</code>. Never a customer's account. The pre-request script skips the request when either variable is empty.</li>\n<li>Always send <code>expectedName</code>: if the account's name in BUSY differs, nothing is changed (<code>409 MASTER_NAME_MISMATCH</code>).</li>\n<li><strong>Never retry a write blindly.</strong> After <code>504 BUSY_WRITE_UNCERTAIN</code>, read the account first (Customer with <code>customerId</code> = <code>accountId</code>) and compare.</li>\n</ul>\n<p><strong>Changeable:</strong> <code>printName</code>, any <code>address</code> member (<code>line1</code>…<code>line4</code>, <code>state</code>, <code>pinCode</code>, <code>station</code>, <code>contactPerson</code>, <code>telephone</code>, <code>mobile</code>, <code>whatsApp</code>, <code>email</code>, <code>gstin</code>, <code>pan</code>), <code>gstRegistrationType</code>, <code>creditDays</code>, <code>creditLimit</code>, and <code>openingBalance</code> with <code>allocation: \"unallocated\"</code> <strong>only</strong> for an account with no opening bill references (otherwise <code>409 MASTER_CHANGE_UNSUPPORTED</code>). <strong>Not changeable here:</strong> name, alias, group, bill references. A body with nothing to change is <code>400</code>.</p>\n<p><strong>Answer (200):</strong> <code>data</code> = <code>{ masterId, name, alias, fields }</code> (<code>fields</code> = only the fields sent, as BUSY stored them); <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, masterType, outcome (modified), verifiedFields, [openingBalanceAllocation], elapsedMs, executedAt</code>.</p>\n<p><strong>Errors:</strong> as create, plus 404 <code>NOT_FOUND</code> (no master with that code, <code>field: accountId</code>), 409 <code>MASTER_TYPE_MISMATCH</code> (the code is not an account), <code>MASTER_NAME_MISMATCH</code>, <code>MASTER_CHANGE_UNSUPPORTED</code>.</p>\n<p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5ab.</p>\n<hr />\n<p><strong>Optional fields (<code>optionalFields</code>; needs a PC build with Windows <code>a20701b</code>).</strong> Optional member keyed by slot <code>OF1</code>-<code>OF10</code> exactly as \"Optional-field definitions\" (Cloud Relay → Master Reads) lists them for the same company and year. Account fields may be text (a string, 1-255 Latin-1 characters without surrounding spaces), dropdown (an existing value), whole number, date or Yes/No, on Access companies and on SQL Server companies with a SQL login (Windows <code>3aa08bf</code>, 29 October 2026); number fields with decimals and other kinds are <code>422 OPTIONAL_FIELD_UNSUPPORTED</code>, and a PC build from before that change also refuses the non-text account kinds on SQL Server that way. Slots you do not send keep their values; <code>null</code> clears a slot; an empty string is refused. The PC checks every value against that year's definition; the cloud forwards the object exactly as sent.</p>\n<p>Add to the body, for example: <code>\"optionalFields\": { \"OF1\": \"Synthetic North\", \"OF2\": null }</code></p>\n<p>A master write never creates a dropdown value: an unknown one is <code>422 OPTIONAL_FIELD_VALUE_NOT_FOUND</code> (nothing written) — add it first with \"⚠ BUSY account dropdown value – create\" (or, for a product, \"⚠ BUSY product dropdown value – create\"). Other refusals: <code>422 OPTIONAL_FIELD_NOT_DEFINED</code> (field <code>optionalFields.OFn</code>), <code>422 OPTIONAL_FIELD_UNSUPPORTED</code>, <code>409 OPTIONAL_FIELD_VALUE_CHANGED</code> — each means nothing was written. On success <code>data.fields.optionalFields</code> echoes each written slot (a dropdown as <code>{ code, name }</code>, a cleared slot as <code>null</code>) and <code>metadata.verifiedFields</code> lists <code>optionalFields.OFn</code>. <code>502 BUSY_WRITE_UNVERIFIED</code> may name a slot in <code>details.mismatchedFields</code>. An earlier PC build refuses the member (<code>400 BAD_REQUEST</code>) and writes nothing. This request's saved body does not send <code>optionalFields</code> (its tests compare the fields sent); add the member when you need it.</p>\n<p><strong>Durable queue:</strong> optional strict <code>queue</code> (omitted or <code>false</code>: synchronous; <code>true</code>: a <code>202</code> job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.</p>\n<hr />\n<p><strong>Parity update (2026-10-23, deployed in release <code>790395a</code>; the PC must be Windows <code>6c5776d</code> or later for these members).</strong> This request's body sends only the basic members. New optional members and codes:</p>\n<ul>\n<li><code>queue</code> (optional, <code>true</code> or <code>false</code>, default <code>false</code>; <code>null</code> is refused <code>400</code>): with <code>true</code> the PC accepts the write on its durable queue and the answer is <strong><code>202</code></strong> with <code>data: null</code> and <code>metadata.queued: true</code>, <code>metadata.jobId</code> (32 hex), <code>metadata.status</code> — acceptance, <strong>not</strong> a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable <code>companyCode</code>/four-digit <code>financialYear</code>; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (<code>202</code>) and fails there. The cloud sends it once.</li>\n<li><code>409 OPTIONAL_FIELD_CONFIGURATION_CHANGED</code>: the year's optional-field configuration changed while the write was prepared; read the definitions again, nothing was written. Account optional fields may be text, dropdown, whole number, date or Yes/No on Access and on SQL Server with a SQL login.</li>\n<li>Shared refusals of every write, answered before anything is written: <code>403 PLAN_FEATURE_NOT_INCLUDED</code>, <code>409 PLAN_NOT_KNOWN</code>, <code>503 BUSY_COM_RECOVERY_REQUIRED</code>, <code>409 BUSY_WRITE_TARGET_CHANGED</code>, <code>422 BUSY_SETTING_REQUIRED</code>, <code>502 BUSY_SETTINGS_UNREADABLE</code>; queue refusals <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>, <code>503 WRITE_QUEUE_UNAVAILABLE</code>.</li>\n<li><code>409 MASTER_REFERENCE_CHANGED</code> (PC from Windows <code>53b556f</code>): a group, unit or tax category the request names changed in BUSY just before the save; nothing was written. Read the references again. Not retryable.</li>\n</ul>\n<p>Scenario requests for the new members are in this folder, named <code>⚠ Scenario – …</code> and <code>⚠ EXPECTED REFUSAL …</code>; they are guarded like this one (<code>confirmMutating</code> = <code>yes</code>, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","account-modify"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"821903fd-4576-9426-b89d-7594e054a366"},{"name":"⚠ BUSY master – create product (writes to BUSY)","id":"915a176d-f2f0-397b-f667-b40a0b65d3fa","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Test Item 01\",\n  \"alias\": \"AZAPI-ITEM-01\",\n  \"parentGroup\": { \"name\": \"General\" },\n  \"mainUnit\": { \"name\": \"Pcs.\" },\n  \"salePrice\": 150,\n  \"purchasePrice\": 100,\n  \"mrp\": 200,\n  \"hsnCode\": \"84713010\",\n  \"descriptionLines\": [\"Synthetic test item\"]\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/product-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/product-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)\n<strong>Status (2026-10-13):</strong> the cloud route is live. Windows relays master writes from source commit <code>6e3f9aa</code> onward (same organization token as the reads; installed on the development PC as candidate <code>586f094</code> and live-tested through the cloud on COMP0002 on 2026-10-13; not released): the BUSY job starts only if it can finish within the command's 400 s, else <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing written; the only write error you may resend); once BUSY is saving it is never stopped; refusals carry <code>metadata.error.details</code>. A PC running an earlier build — every released version up to 0.0.11 — answers <code>502 DEVICE_ERROR</code> (<code>REPORT_UNSUPPORTED</code>) and writes nothing. The cloud publishes a write once, never retries it, and answers <code>504 WRITE_RESULT_UNKNOWN</code> when the PC's result does not arrive in time: look the master up before trying again.\n<strong>Required:</strong> see the Local request · operation <code>busy.products.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body as the Local request; the text below is the Local request's description.</strong></p>\n<p><strong>Mutating — writes to the BUSY books. Run manually, one at a time.</strong> <code>busy.products.create</code> (<code>POST /api/v1/product-create</code>) creates one BUSY product (item) through BUSY's own COM component on this PC, then reads it back and checks every field you sent before answering. SQL Server companies with a SQL login, and Access companies (Windows <code>6c5776d</code> or later; an earlier PC answers Access with <code>409 MASTER_WRITE_PROVIDER_UNSUPPORTED</code>). Never an upsert. For Cloud Relay, a compatible Windows agent is required; an older agent may refuse without writing. See Cloud Relay → ⚠ Master Create &amp; Modify. Never run this write from scripts.</p>\n<p><strong>Safe test guidance</strong></p>\n<ul>\n<li>Use only a <strong>development-test company</strong> (<code>targetCompanyCode</code>) and a <strong>new, unique test name</strong> (change <code>name</code> and <code>alias</code> before each send). Never a customer's company. Created test products stay in BUSY.</li>\n<li>The example sends <strong>no opening stock</strong> on purpose (it is part of the books). Add it only on a test product, deliberately.</li>\n<li><strong>Never retry a write blindly</strong>: a second send of the same body is refused (<code>409 MASTER_NAME_TAKEN</code>) if the first saved; after <code>504 BUSY_WRITE_UNCERTAIN</code> look the product up (Products search) first.</li>\n<li>References (<code>parentGroup</code>, <code>mainUnit</code>, <code>alternateUnit.unit</code>, <code>taxCategory</code>, <code>openingStock.materialCenter</code>) must exist in the company; a name more than one master shares is <code>422 MASTER_REFERENCE_AMBIGUOUS</code>.</li>\n</ul>\n<p><strong>Body:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>name</code> (1-40, required), <code>alias</code>, <code>printName</code> (1-60), <code>parentGroup</code> (required, item group <code>{\"code\": n}</code> or <code>{\"name\": \"…\"}</code>), <code>mainUnit</code> (required), <code>alternateUnit</code> (<code>{\"unit\": {\"name\": \"Dozen\"}, \"conversionFactor\": 12}</code>), <code>salePrice</code>, <code>purchasePrice</code>, <code>mrp</code> (≥ 0, ≤ 4 decimals), <code>salesDiscountPercent</code>, <code>purchaseDiscountPercent</code> (0-100), <code>hsnCode</code> (4-8 digits), <code>taxCategory</code> (e.g. <code>{\"name\": \"GST 18%\"}</code>; BUSY sets the rates from it), <code>descriptionLines</code> (1-4 lines of 1-40), <code>openingStock</code> (<code>{\"quantity\": 10, \"amount\": 1000, \"materialCenter\": {\"name\": \"Main Store\"}}</code>; one godown, conversion factor 1 only).</p>\n<p><strong>Answer (200):</strong> <code>data</code> = <code>{ masterId, name, alias, fields }</code>; <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, masterType (product), outcome (created), verifiedFields, elapsedMs, executedAt</code>. The test stores <code>masterProductId</code> / <code>masterProductName</code> for the modify request.</p>\n<p><strong>Errors:</strong> as account create (400, 403, 404, 409 <code>MASTER_NAME_TAKEN</code> / <code>MASTER_WRITE_PROVIDER_UNSUPPORTED</code>, 422 references, 502 <code>BUSY_WRITE_FAILED</code> / <code>BUSY_WRITE_UNVERIFIED</code>, 503 <code>BUSY_COM_*</code>, 504 <code>BUSY_WRITE_UNCERTAIN</code> / <code>BUSY_COM_TIMEOUT</code>).</p>\n<p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5ab.</p>\n<hr />\n<p><strong>Optional fields (<code>optionalFields</code>; needs a PC build with Windows <code>a20701b</code>).</strong> Optional member keyed by slot <code>OF1</code>-<code>OF10</code> exactly as \"Optional-field definitions\" (Cloud Relay → Master Reads) lists them for the same company and year. Product fields: text (a string, 1-255 Latin-1 characters without surrounding spaces), dropdown (<code>{ \"code\": n }</code> or <code>{ \"name\": \"…\" }</code> of an <strong>existing</strong> value), number (a whole number; fields with decimals are refused), date (<code>\"YYYY-MM-DD\"</code>, 1900-2099), Yes/No (<code>true</code>/<code>false</code>). A create cannot clear a slot (<code>null</code> is refused: <code>400 INVALID_PARAMETER</code>, field <code>optionalFields.OFn</code>); an empty string is refused. The PC checks every value against that year's definition; the cloud forwards the object exactly as sent.</p>\n<p>Add to the body, for example: <code>\"optionalFields\": { \"OF1\": { \"name\": \"Synthetic Acme\" }, \"OF2\": \"Synthetic Blue\", \"OF3\": 12, \"OF4\": \"2026-10-17\", \"OF5\": true }</code></p>\n<p>A master write never creates a dropdown value: an unknown one is <code>422 OPTIONAL_FIELD_VALUE_NOT_FOUND</code> (nothing written) — add it first with \"⚠ BUSY product dropdown value – create\". Other refusals: <code>422 OPTIONAL_FIELD_NOT_DEFINED</code> (field <code>optionalFields.OFn</code>), <code>422 OPTIONAL_FIELD_UNSUPPORTED</code>, <code>409 OPTIONAL_FIELD_VALUE_CHANGED</code> — each means nothing was written. On success <code>data.fields.optionalFields</code> echoes each written slot (a dropdown as <code>{ code, name }</code>, a cleared slot as <code>null</code>) and <code>metadata.verifiedFields</code> lists <code>optionalFields.OFn</code>. <code>502 BUSY_WRITE_UNVERIFIED</code> may name a slot in <code>details.mismatchedFields</code>. An earlier PC build refuses the member (<code>400 BAD_REQUEST</code>) and writes nothing. This request's saved body does not send <code>optionalFields</code> (its tests compare the fields sent); add the member when you need it.</p>\n<p><strong>Durable queue:</strong> optional strict <code>queue</code> (omitted or <code>false</code>: synchronous; <code>true</code>: a <code>202</code> job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.</p>\n<hr />\n<p><strong>Parity update (2026-10-23, deployed in release <code>790395a</code>; the PC must be Windows <code>6c5776d</code> or later for these members).</strong> This request's body sends only the basic members. New optional members and codes:</p>\n<ul>\n<li><code>queue</code> (optional, <code>true</code> or <code>false</code>, default <code>false</code>; <code>null</code> is refused <code>400</code>): with <code>true</code> the PC accepts the write on its durable queue and the answer is <strong><code>202</code></strong> with <code>data: null</code> and <code>metadata.queued: true</code>, <code>metadata.jobId</code> (32 hex), <code>metadata.status</code> — acceptance, <strong>not</strong> a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable <code>companyCode</code>/four-digit <code>financialYear</code>; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (<code>202</code>) and fails there. The cloud sends it once.</li>\n<li><code>409 OPTIONAL_FIELD_CONFIGURATION_CHANGED</code>: the year's optional-field configuration changed while the write was prepared; read the definitions again, nothing was written.</li>\n<li>Shared refusals of every write, answered before anything is written: <code>403 PLAN_FEATURE_NOT_INCLUDED</code>, <code>409 PLAN_NOT_KNOWN</code>, <code>503 BUSY_COM_RECOVERY_REQUIRED</code>, <code>409 BUSY_WRITE_TARGET_CHANGED</code>, <code>422 BUSY_SETTING_REQUIRED</code>, <code>502 BUSY_SETTINGS_UNREADABLE</code>; queue refusals <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>, <code>503 WRITE_QUEUE_UNAVAILABLE</code>.</li>\n<li><code>409 MASTER_REFERENCE_CHANGED</code> (PC from Windows <code>53b556f</code>): a group, unit or tax category the request names changed in BUSY just before the save; nothing was written. Read the references again. Not retryable.</li>\n</ul>\n<p>Scenario requests for the new members are in this folder, named <code>⚠ Scenario – …</code> and <code>⚠ EXPECTED REFUSAL …</code>; they are guarded like this one (<code>confirmMutating</code> = <code>yes</code>, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","product-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"915a176d-f2f0-397b-f667-b40a0b65d3fa"},{"name":"⚠ BUSY master – modify product (writes to BUSY)","id":"15340ba1-d203-4ab1-eb07-fc92843f6c38","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"productId\": {{masterProductId}},\n  \"expectedName\": \"{{masterProductName}}\",\n  \"salePrice\": 160,\n  \"mrp\": 210\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/product-modify","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/product-modify</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)\n<strong>Status (2026-10-13):</strong> the cloud route is live. Windows relays master writes from source commit <code>6e3f9aa</code> onward (same organization token as the reads; installed on the development PC as candidate <code>586f094</code> and live-tested through the cloud on COMP0002 on 2026-10-13; not released): the BUSY job starts only if it can finish within the command's 400 s, else <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing written; the only write error you may resend); once BUSY is saving it is never stopped; refusals carry <code>metadata.error.details</code>. A PC running an earlier build — every released version up to 0.0.11 — answers <code>502 DEVICE_ERROR</code> (<code>REPORT_UNSUPPORTED</code>) and writes nothing. The cloud publishes a write once, never retries it, and answers <code>504 WRITE_RESULT_UNKNOWN</code> when the PC's result does not arrive in time: look the master up before trying again.\n<strong>Required:</strong> see the Local request · operation <code>busy.products.modify</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body as the Local request; the text below is the Local request's description.</strong></p>\n<p><strong>Mutating — writes to the BUSY books. Run manually, one at a time.</strong> <code>busy.products.modify</code> (<code>POST /api/v1/product-modify</code>) changes only the fields you send of one existing BUSY product, named by BUSY's code (<code>productId</code> = <code>product_id</code> in the product operations). BUSY's own record is read, edited and saved; every other field stays as it is, and the record is compared before and after. SQL Server companies with a SQL login, and Access companies (Windows <code>6c5776d</code> or later; an earlier PC answers Access with <code>409 MASTER_WRITE_PROVIDER_UNSUPPORTED</code>). For Cloud Relay, a compatible Windows agent is required; an older agent may refuse without writing. See Cloud Relay → ⚠ Master Create &amp; Modify. Never run this write from scripts.</p>\n<p><strong>Safe test guidance</strong></p>\n<ul>\n<li>Change <strong>only a test product you created yourself</strong> — the create request stores <code>masterProductId</code> and <code>masterProductName</code>. Never a customer's product. The pre-request script skips the request when either variable is empty.</li>\n<li>Always send <code>expectedName</code> (nothing is changed when it differs: <code>409 MASTER_NAME_MISMATCH</code>).</li>\n<li><strong>Never retry a write blindly.</strong> After <code>504 BUSY_WRITE_UNCERTAIN</code>, read the product first and compare.</li>\n</ul>\n<p><strong>Changeable:</strong> <code>printName</code>, <code>salePrice</code>, <code>purchasePrice</code>, <code>mrp</code>, <code>salesDiscountPercent</code>, <code>purchaseDiscountPercent</code>, <code>hsnCode</code>, <code>taxCategory</code>, <code>descriptionLines</code> (lines not sent keep their text), and <code>openingStock</code> (<code>{quantity, amount, materialCenter}</code>) <strong>only</strong> in the one godown the product's opening stock is already in, with a conversion factor of 1 (otherwise <code>409 MASTER_CHANGE_UNSUPPORTED</code>). <strong>Not changeable here:</strong> name, alias, group, units.</p>\n<p><strong>Answer (200):</strong> <code>data</code> = <code>{ masterId, name, alias, fields }</code> (only the fields sent); <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, masterType (product), outcome (modified), verifiedFields, elapsedMs, executedAt</code>.</p>\n<p><strong>Errors:</strong> as product create, plus 404 <code>NOT_FOUND</code> (<code>field: productId</code>), 409 <code>MASTER_TYPE_MISMATCH</code> (the code is not a product), <code>MASTER_NAME_MISMATCH</code>, <code>MASTER_CHANGE_UNSUPPORTED</code>.</p>\n<p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>. Canonical contract: <code>docs/LOCAL-API.md</code> section 5ab.</p>\n<hr />\n<p><strong>Optional fields (<code>optionalFields</code>; needs a PC build with Windows <code>a20701b</code>).</strong> Optional member keyed by slot <code>OF1</code>-<code>OF10</code> exactly as \"Optional-field definitions\" (Cloud Relay → Master Reads) lists them for the same company and year. Product fields: text (a string, 1-255 Latin-1 characters without surrounding spaces), dropdown (<code>{ \"code\": n }</code> or <code>{ \"name\": \"…\" }</code> of an <strong>existing</strong> value), number (a whole number; fields with decimals are refused), date (<code>\"YYYY-MM-DD\"</code>, 1900-2099), Yes/No (<code>true</code>/<code>false</code>). Slots you do not send keep their values; <code>null</code> clears a slot; an empty string is refused. The PC checks every value against that year's definition; the cloud forwards the object exactly as sent.</p>\n<p>Add to the body, for example: <code>\"optionalFields\": { \"OF1\": { \"name\": \"Synthetic Acme\" }, \"OF2\": \"Synthetic Blue\", \"OF3\": 12, \"OF4\": \"2026-10-17\", \"OF5\": true, \"OF6\": null }</code></p>\n<p>A master write never creates a dropdown value: an unknown one is <code>422 OPTIONAL_FIELD_VALUE_NOT_FOUND</code> (nothing written) — add it first with \"⚠ BUSY product dropdown value – create\". Other refusals: <code>422 OPTIONAL_FIELD_NOT_DEFINED</code> (field <code>optionalFields.OFn</code>), <code>422 OPTIONAL_FIELD_UNSUPPORTED</code>, <code>409 OPTIONAL_FIELD_VALUE_CHANGED</code> — each means nothing was written. On success <code>data.fields.optionalFields</code> echoes each written slot (a dropdown as <code>{ code, name }</code>, a cleared slot as <code>null</code>) and <code>metadata.verifiedFields</code> lists <code>optionalFields.OFn</code>. <code>502 BUSY_WRITE_UNVERIFIED</code> may name a slot in <code>details.mismatchedFields</code>. An earlier PC build refuses the member (<code>400 BAD_REQUEST</code>) and writes nothing. This request's saved body does not send <code>optionalFields</code> (its tests compare the fields sent); add the member when you need it.</p>\n<p><strong>Durable queue:</strong> optional strict <code>queue</code> (omitted or <code>false</code>: synchronous; <code>true</code>: a <code>202</code> job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.</p>\n<hr />\n<p><strong>Parity update (2026-10-23, deployed in release <code>790395a</code>; the PC must be Windows <code>6c5776d</code> or later for these members).</strong> This request's body sends only the basic members. New optional members and codes:</p>\n<ul>\n<li><code>queue</code> (optional, <code>true</code> or <code>false</code>, default <code>false</code>; <code>null</code> is refused <code>400</code>): with <code>true</code> the PC accepts the write on its durable queue and the answer is <strong><code>202</code></strong> with <code>data: null</code> and <code>metadata.queued: true</code>, <code>metadata.jobId</code> (32 hex), <code>metadata.status</code> — acceptance, <strong>not</strong> a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable <code>companyCode</code>/four-digit <code>financialYear</code>; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (<code>202</code>) and fails there. The cloud sends it once.</li>\n<li><code>409 OPTIONAL_FIELD_CONFIGURATION_CHANGED</code>: the year's optional-field configuration changed while the write was prepared; read the definitions again, nothing was written.</li>\n<li>Shared refusals of every write, answered before anything is written: <code>403 PLAN_FEATURE_NOT_INCLUDED</code>, <code>409 PLAN_NOT_KNOWN</code>, <code>503 BUSY_COM_RECOVERY_REQUIRED</code>, <code>409 BUSY_WRITE_TARGET_CHANGED</code>, <code>422 BUSY_SETTING_REQUIRED</code>, <code>502 BUSY_SETTINGS_UNREADABLE</code>; queue refusals <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>, <code>503 WRITE_QUEUE_UNAVAILABLE</code>.</li>\n<li><code>409 MASTER_REFERENCE_CHANGED</code> (PC from Windows <code>53b556f</code>): a group, unit or tax category the request names changed in BUSY just before the save; nothing was written. Read the references again. Not retryable.</li>\n</ul>\n<p>Scenario requests for the new members are in this folder, named <code>⚠ Scenario – …</code> and <code>⚠ EXPECTED REFUSAL …</code>; they are guarded like this one (<code>confirmMutating</code> = <code>yes</code>, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","product-modify"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"15340ba1-d203-4ab1-eb07-fc92843f6c38"},{"name":"⚠ BUSY product dropdown value – create (writes to BUSY)","id":"0cef53b2-591b-2100-d900-d390e09533ca","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"slot\": \"{{optionalFieldSlot}}\",\n  \"name\": \"{{optionalFieldValueName}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/product-optional-field-value-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/product-optional-field-value-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)\n<strong>Status (2026-10-23):</strong> deployed and live (release <code>790395a</code>). The PC side is in released AI Zeny 0.0.14 (Windows <code>a20701b</code>, installed service-account acceptance passed); an earlier PC build answers <code>502 DEVICE_ERROR</code> and writes nothing. The cloud publishes a write once, never retries it, and answers <code>504 WRITE_RESULT_UNKNOWN</code> when the PC's result does not arrive in time.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>slot</code>, <code>name</code> · operation <code>busy.products.optional-field-values.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books. Run manually, one at a time.</strong> Adds one new value to an ITEM (product) dropdown optional field through BUSY's own component on the PC, then reads the list again to confirm exactly that value was added. Use it before a product create/modify names a value the dropdown does not have yet: the master writes never create one (<code>422 OPTIONAL_FIELD_VALUE_NOT_FOUND</code>).</p>\n<p><strong>Variables:</strong> <code>optionalFieldSlot</code> — the item dropdown's slot from \"Optional-field definitions\" (Cloud Relay → Master Reads) for the same year; <code>optionalFieldValueName</code> — a NEW synthetic name, 1-40 Latin-1 characters without leading or trailing spaces. Both variables are blank safe placeholders in the existing development environment. The pre-request script skips unless the slot is OF1–OF10, the name is a fresh 1–40 printable Latin-1 character synthetic value, and one-send confirmation is set. Set only after reading this company's item dropdown definitions; no credential is supplied.</p>\n<p><strong>Body:</strong> <code>companyCode, financialYear, slot (OF1-OF10), name.</code></p>\n<p><strong>Answer (200):</strong> <code>data</code> = <code>{ valueId, slot, listType (200 + slot), name }</code>; <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, outcome (created), verifiedFields ([\"slot\", \"name\"]), elapsedMs, executedAt</code>.</p>\n<p><strong>Errors:</strong> 409 <code>OPTIONAL_FIELD_VALUE_TAKEN</code> (field <code>name</code>; the list already has the name, compared without case — <code>details.masterId</code> is the existing value's code; nothing created), 422 <code>OPTIONAL_FIELD_NOT_DEFINED</code> / <code>OPTIONAL_FIELD_UNSUPPORTED</code> (field <code>slot</code>: no item field there, or not a dropdown), 409 <code>MASTER_WRITE_PROVIDER_UNSUPPORTED</code>, 409 <code>BUSY_COM_SIGN_IN_UNSUPPORTED</code> (a SQL Server company that signs in with Windows), 502 <code>BUSY_WRITE_FAILED</code> / <code>BUSY_WRITE_UNVERIFIED</code>, 504 <code>BUSY_WRITE_UNCERTAIN</code> / <code>WRITE_RESULT_UNKNOWN</code> (never resend blind: read the definitions first), 503 <code>BUSY_COM_QUEUE_TIMEOUT</code> (the only retryable code).</p>\n<p><strong>Not offered:</strong> creating or changing optional-field definitions. Account dropdown values have their own route, <code>POST /v1/account-optional-field-value-create</code>.</p>\n<p>Guard: skipped unless <code>confirmMutating</code> = <code>yes</code>.</p>\n<p><strong>Durable queue:</strong> optional strict <code>queue</code> (omitted or <code>false</code>: synchronous; <code>true</code>: a <code>202</code> job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.</p>\n<hr />\n<p><strong>Parity update (2026-10-23, deployed in release <code>790395a</code>; the PC must be Windows <code>6c5776d</code> or later for these members).</strong> This request's body sends only the basic members. New optional members and codes:</p>\n<ul>\n<li><code>queue</code> (optional, <code>true</code> or <code>false</code>, default <code>false</code>; <code>null</code> is refused <code>400</code>): with <code>true</code> the PC accepts the write on its durable queue and the answer is <strong><code>202</code></strong> with <code>data: null</code> and <code>metadata.queued: true</code>, <code>metadata.jobId</code> (32 hex), <code>metadata.status</code> — acceptance, <strong>not</strong> a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable <code>companyCode</code>/four-digit <code>financialYear</code>; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (<code>202</code>) and fails there. The cloud sends it once.</li>\n<li><code>409 OPTIONAL_FIELD_CONFIGURATION_CHANGED</code>: the year's optional-field configuration changed while the write was prepared; read the definitions again, nothing was written. The account counterpart is <code>POST /v1/account-optional-field-value-create</code>.</li>\n<li>Shared refusals of every write, answered before anything is written: <code>403 PLAN_FEATURE_NOT_INCLUDED</code>, <code>409 PLAN_NOT_KNOWN</code>, <code>503 BUSY_COM_RECOVERY_REQUIRED</code>, <code>409 BUSY_WRITE_TARGET_CHANGED</code>, <code>422 BUSY_SETTING_REQUIRED</code>, <code>502 BUSY_SETTINGS_UNREADABLE</code>; queue refusals <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>, <code>503 WRITE_QUEUE_UNAVAILABLE</code>.</li>\n</ul>\n<p>Scenario requests for the new members are in this folder, named <code>⚠ Scenario – …</code> and <code>⚠ EXPECTED REFUSAL …</code>; they are guarded like this one (<code>confirmMutating</code> = <code>yes</code>, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","product-optional-field-value-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"0cef53b2-591b-2100-d900-d390e09533ca"},{"name":"⚠ BUSY group – create account group (writes to BUSY)","id":"caf6d622-c6a4-8df9-b93b-9aae8f7ffea3","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Cloud Account Group 01\",\n  \"alias\": \"AZAPI-CAG-01\",\n  \"parentGroup\": {\n    \"name\": \"Sundry Debtors\"\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/account-group-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/account-group-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.account-groups.create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Body</strong> (small; the PC also accepts at most 64 KiB per signed command): companyCode, financialYear, name (string), and exactly one of parentGroup ({code} or {name}, a group of the same type) or topLevel (true); optionally alias. Optional queue (boolean, default false).</p>\n<p><strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it. <strong>200</strong> <code>data</code> = { groupId (BUSY's code), name, alias (or null), topLevel, parentGroup ({ code, name } or null at top level), path ([{ code, name }] from the top-level group down to the parent; empty at top level) } — read again from BUSY's database. <code>metadata</code> = apiVersion, operation, requestId, companyCode, financialYear, masterType (\"accountGroup\"), outcome (\"created\"), verifiedFields[], descendantGroups (groups below it, unchanged), elapsedMs, executedAt.</p>\n<p><strong>Before sending:</strong> set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY. On success the test stores <code>cloudAccountGroupId</code>.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Look the group up in BUSY by its name; creating it again answers 409 MASTER_NAME_TAKEN. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p><strong>Route errors:</strong> 409 MASTER_NAME_TAKEN field name or alias (a create never changes an existing group); 422 MASTER_REFERENCE_NOT_FOUND / MASTER_REFERENCE_AMBIGUOUS field parentGroup (no single group of the same type has that code or name), 422 GROUP_PARENT_INVALID field parentGroup, 409 GROUP_PARENT_CHANGED field parentGroup (the parent changed in BUSY just before the save), 422 BUSY_GROUP_HIERARCHY_INVALID / BUSY_DATA_INCONSISTENT (BUSY's stored hierarchy); each: nothing written. Plus the shared write refusals (plan, BUSY COM, changed destination, settings, queue) in the operations reference.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","account-group-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"caf6d622-c6a4-8df9-b93b-9aae8f7ffea3"},{"name":"⚠ BUSY group – modify account group (writes to BUSY)","id":"1c99ec31-af7b-10f8-96c9-f18ec80439ea","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"groupId\": {{cloudAccountGroupId}},\n  \"expectedName\": \"AZAPI Cloud Account Group 01\",\n  \"alias\": \"AZAPI-CAG-01M\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/account-group-modify","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/account-group-modify</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.account-groups.modify</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Body</strong> (small; the PC also accepts at most 64 KiB per signed command): companyCode, financialYear, groupId (number), optionally expectedName, and at least one of name, alias or removeAlias (true), parentGroup ({code} or {name}) or moveToTopLevel (true). Optional queue (boolean, default false).</p>\n<p><strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it. <strong>200</strong> <code>data</code> = { groupId (BUSY's code), name, alias (or null), topLevel, parentGroup ({ code, name } or null at top level), path ([{ code, name }] from the top-level group down to the parent; empty at top level) } — read again from BUSY's database. <code>metadata</code> = apiVersion, operation, requestId, companyCode, financialYear, masterType (\"accountGroup\"), outcome (\"modified\"), verifiedFields[], descendantGroups (groups below it, unchanged), elapsedMs, executedAt.</p>\n<p><strong>Before sending:</strong> set <code>cloudAccountGroupId</code> (current values; the request is skipped until they are set), set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Read the group in BUSY; a modify sent again with the same values changes nothing new. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p><strong>Route errors:</strong> 404 NOT_FOUND field groupId, 409 MASTER_TYPE_MISMATCH field groupId (the code is not a group of this type), 409 MASTER_NAME_MISMATCH field expectedName, 409 GROUP_PREDEFINED field groupId (one of BUSY's standard groups), 409 MASTER_CHANGE_UNSUPPORTED (a move of a group that holds masters, or has a group below it that does); each: nothing changed; 409 MASTER_NAME_TAKEN field name or alias (another group of the type has it as its name or alias); 422 MASTER_REFERENCE_NOT_FOUND / MASTER_REFERENCE_AMBIGUOUS field parentGroup (no single group of the same type has that code or name), 422 GROUP_PARENT_INVALID field parentGroup, 409 GROUP_PARENT_CHANGED field parentGroup (the parent changed in BUSY just before the save), 422 BUSY_GROUP_HIERARCHY_INVALID / BUSY_DATA_INCONSISTENT (BUSY's stored hierarchy); each: nothing written. Plus the shared write refusals (plan, BUSY COM, changed destination, settings, queue) in the operations reference.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","account-group-modify"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"1c99ec31-af7b-10f8-96c9-f18ec80439ea"},{"name":"⚠ BUSY group – create product group (writes to BUSY)","id":"bc3108d2-7f05-332f-692d-bfe38db42b36","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Cloud Product Group 01\",\n  \"parentGroup\": {\n    \"name\": \"General\"\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/product-group-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/product-group-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.product-groups.create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Body</strong> (small; the PC also accepts at most 64 KiB per signed command): companyCode, financialYear, name (string), and exactly one of parentGroup ({code} or {name}, a group of the same type) or topLevel (true); optionally alias. Optional queue (boolean, default false).</p>\n<p><strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it. <strong>200</strong> <code>data</code> = { groupId (BUSY's code), name, alias (or null), topLevel, parentGroup ({ code, name } or null at top level), path ([{ code, name }] from the top-level group down to the parent; empty at top level) } — read again from BUSY's database. <code>metadata</code> = apiVersion, operation, requestId, companyCode, financialYear, masterType (\"productGroup\"), outcome (\"created\"), verifiedFields[], descendantGroups (groups below it, unchanged), elapsedMs, executedAt.</p>\n<p><strong>Before sending:</strong> set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY. On success the test stores <code>cloudProductGroupId</code>.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Look the group up in BUSY by its name; creating it again answers 409 MASTER_NAME_TAKEN. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p><strong>Route errors:</strong> 409 MASTER_NAME_TAKEN field name or alias (a create never changes an existing group); 422 MASTER_REFERENCE_NOT_FOUND / MASTER_REFERENCE_AMBIGUOUS field parentGroup (no single group of the same type has that code or name), 422 GROUP_PARENT_INVALID field parentGroup, 409 GROUP_PARENT_CHANGED field parentGroup (the parent changed in BUSY just before the save), 422 BUSY_GROUP_HIERARCHY_INVALID / BUSY_DATA_INCONSISTENT (BUSY's stored hierarchy); each: nothing written. Plus the shared write refusals (plan, BUSY COM, changed destination, settings, queue) in the operations reference.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","product-group-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"bc3108d2-7f05-332f-692d-bfe38db42b36"},{"name":"⚠ BUSY group – modify product group (writes to BUSY)","id":"9f140b7e-c871-808d-a7ac-f20d4dea7003","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"groupId\": {{cloudProductGroupId}},\n  \"expectedName\": \"AZAPI Cloud Product Group 01\",\n  \"alias\": \"AZAPI-CPG-01M\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/product-group-modify","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/product-group-modify</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.product-groups.modify</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Body</strong> (small; the PC also accepts at most 64 KiB per signed command): companyCode, financialYear, groupId (number), optionally expectedName, and at least one of name, alias or removeAlias (true), parentGroup ({code} or {name}) or moveToTopLevel (true). Optional queue (boolean, default false).</p>\n<p><strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it. <strong>200</strong> <code>data</code> = { groupId (BUSY's code), name, alias (or null), topLevel, parentGroup ({ code, name } or null at top level), path ([{ code, name }] from the top-level group down to the parent; empty at top level) } — read again from BUSY's database. <code>metadata</code> = apiVersion, operation, requestId, companyCode, financialYear, masterType (\"productGroup\"), outcome (\"modified\"), verifiedFields[], descendantGroups (groups below it, unchanged), elapsedMs, executedAt.</p>\n<p><strong>Before sending:</strong> set <code>cloudProductGroupId</code> (current values; the request is skipped until they are set), set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Read the group in BUSY; a modify sent again with the same values changes nothing new. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p><strong>Route errors:</strong> 404 NOT_FOUND field groupId, 409 MASTER_TYPE_MISMATCH field groupId (the code is not a group of this type), 409 MASTER_NAME_MISMATCH field expectedName, 409 GROUP_PREDEFINED field groupId (one of BUSY's standard groups), 409 MASTER_CHANGE_UNSUPPORTED (a move of a group that holds masters, or has a group below it that does); each: nothing changed; 409 MASTER_NAME_TAKEN field name or alias (another group of the type has it as its name or alias); 422 MASTER_REFERENCE_NOT_FOUND / MASTER_REFERENCE_AMBIGUOUS field parentGroup (no single group of the same type has that code or name), 422 GROUP_PARENT_INVALID field parentGroup, 409 GROUP_PARENT_CHANGED field parentGroup (the parent changed in BUSY just before the save), 422 BUSY_GROUP_HIERARCHY_INVALID / BUSY_DATA_INCONSISTENT (BUSY's stored hierarchy); each: nothing written. Plus the shared write refusals (plan, BUSY COM, changed destination, settings, queue) in the operations reference.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","product-group-modify"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"9f140b7e-c871-808d-a7ac-f20d4dea7003"},{"name":"⚠ BUSY contact – create (writes to BUSY)","id":"1bcba7c1-3af0-b1bb-6574-f4229a81d584","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"name\": \"AZAPI Cloud Contact 01\",\n  \"contactGroup\": {\n    \"name\": \"General\"\n  },\n  \"salutation\": {\n    \"name\": \"Ms.\"\n  },\n  \"address\": {\n    \"line1\": \"1 Example Road\",\n    \"country\": {\n      \"name\": \"India\"\n    },\n    \"state\": {\n      \"name\": \"Delhi\"\n    },\n    \"mobile\": \"9000000201\",\n    \"email\": \"cloudcontact01@example.invalid\"\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/contact-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/contact-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.contacts.create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Body</strong> (small; the PC also accepts at most 64 KiB per signed command): companyCode, financialYear, name (string), contactGroup ({code} or {name}), address {country ({code} or {name}), and optionally line1-line4, state, pinCode, station, telephone, mobile, whatsApp, fax, email}, and optionally alias, printName, salutation ({code} or {name}), account ({code} or {name}: links the contact). Optional queue (boolean, default false).</p>\n<p><strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it. <strong>200</strong> <code>data</code> = { contactId (BUSY's code), name, alias, printName (or null), contactGroup { code, name }, salutation ({ code, name } or null), linked (the link flag is the truth), account ({ code, name } or null when unlinked), address { line1-line4, country, state ({ code, name } or null), pinCode, station, telephone, mobile, whatsApp, fax, email } } — read again from BUSY. <code>metadata</code> = apiVersion, operation, requestId, companyCode, financialYear, masterType (\"contact\"), outcome (\"created\"), verifiedFields[], elapsedMs, executedAt.</p>\n<p><strong>Before sending:</strong> set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY. On success the test stores <code>cloudContactId</code>.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Look the contact up in BUSY by its name; creating it again answers 409 MASTER_NAME_TAKEN. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p><strong>Route errors:</strong> 422 MASTER_REFERENCE_NOT_FOUND / MASTER_REFERENCE_AMBIGUOUS (the field names the contact group, account, salutation, country or state: masters are never created), 409 CONTACT_REFERENCE_CHANGED (a named master changed just before the save); nothing written; 409 MASTER_NAME_TAKEN field name or alias (another contact has it). Plus the shared write refusals (plan, BUSY COM, changed destination, settings, queue) in the operations reference.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","contact-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"1bcba7c1-3af0-b1bb-6574-f4229a81d584"},{"name":"⚠ BUSY contact – modify, link or unlink (writes to BUSY)","id":"cfa1ab64-3f17-8444-1c3e-5866caca5e3d","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"contactId\": {{cloudContactId}},\n  \"expectedName\": \"AZAPI Cloud Contact 01\",\n  \"address\": {\n    \"mobile\": \"9000000202\",\n    \"whatsApp\": \"9000000202\"\n  },\n  \"clear\": [\n    \"address.line2\"\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/contact-modify","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/contact-modify</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.contacts.modify</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Body</strong> (small; the PC also accepts at most 64 KiB per signed command): companyCode, financialYear, contactId (number), optionally expectedName, and at least one of name, alias, removeAlias (true), printName, contactGroup, salutation, account, unlinkAccount (true), address {line1-line4, country, state, pinCode, station, telephone, mobile, whatsApp, fax, email}, clear (a list of field names). Optional queue (boolean, default false).</p>\n<p><strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it. <strong>200</strong> <code>data</code> = { contactId (BUSY's code), name, alias, printName (or null), contactGroup { code, name }, salutation ({ code, name } or null), linked (the link flag is the truth), account ({ code, name } or null when unlinked), address { line1-line4, country, state ({ code, name } or null), pinCode, station, telephone, mobile, whatsApp, fax, email } } — read again from BUSY. <code>metadata</code> = apiVersion, operation, requestId, companyCode, financialYear, masterType (\"contact\"), outcome (\"modified\"), verifiedFields[], elapsedMs, executedAt.</p>\n<p><strong>Before sending:</strong> set <code>cloudContactId</code> (current values; the request is skipped until they are set), set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Read the contact in BUSY; a modify sent again with the same values changes nothing new. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p><strong>Route errors:</strong> 404 NOT_FOUND field contactId, 409 MASTER_TYPE_MISMATCH field contactId, 409 MASTER_NAME_MISMATCH field expectedName, 409 MASTER_CHANGE_UNSUPPORTED; each: nothing changed; 422 CONTACT_COUNTRY_REQUIRED field address.country (the stored country is not a country master: send address.country with the change), 422 BUSY_DATA_INCONSISTENT (BUSY's record of this contact is not consistent; nothing changed); 422 MASTER_REFERENCE_NOT_FOUND / MASTER_REFERENCE_AMBIGUOUS (the field names the contact group, account, salutation, country or state: masters are never created), 409 CONTACT_REFERENCE_CHANGED (a named master changed just before the save); nothing written; 409 MASTER_NAME_TAKEN field name or alias (another contact has it). Plus the shared write refusals (plan, BUSY COM, changed destination, settings, queue) in the operations reference.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","contact-modify"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"cfa1ab64-3f17-8444-1c3e-5866caca5e3d"},{"name":"⚠ BUSY account dropdown value – create (writes to BUSY)","id":"6ff6f152-8e6e-b544-ea97-f8343d7a3ab6","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"slot\": \"{{accountOptionalFieldSlot}}\",\n  \"name\": \"{{accountOptionalFieldValueName}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/account-optional-field-value-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/account-optional-field-value-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.accounts.optional-field-values.create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Companies:</strong> Access, and SQL Server with a SQL login (Windows <code>3aa08bf</code>, 29 October 2026). A PC build from before that change refuses a SQL Server company's account dropdown with <code>422 OPTIONAL_FIELD_UNSUPPORTED</code> (field <code>slot</code>) and writes nothing.</p>\n<p><strong>Body</strong> (small; the PC also accepts at most 64 KiB per signed command): companyCode, financialYear, slot (OF1-OF10), name. Optional queue (boolean, default false).</p>\n<p><strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it. <strong>200</strong> <code>data</code> = { valueId (BUSY's code of the new value), slot, listType (BUSY's list master type), name (as stored) }. <code>metadata</code> = apiVersion, operation (\"busy.accounts.optional-field-values.create\"), requestId, companyCode, financialYear, outcome (\"created\"), verifiedFields ([\"slot\", \"name\"]), elapsedMs, executedAt.</p>\n<p><strong>Before sending:</strong> set <code>accountOptionalFieldSlot</code>, <code>accountOptionalFieldValueName</code> (current values; the request is skipped until they are set), set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Read Optional-field definitions first: a saved value is listed, and creating it again is 409 OPTIONAL_FIELD_VALUE_TAKEN. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p><strong>Route errors:</strong> 409 OPTIONAL_FIELD_VALUE_TAKEN field name (the list already has the name, compared without case: details.masterId is the existing value's code; nothing created); 422 OPTIONAL_FIELD_NOT_DEFINED field slot (no account field in this slot this year), 422 OPTIONAL_FIELD_UNSUPPORTED field slot (the account field is not a dropdown); nothing written. 409 MASTER_WRITE_PROVIDER_UNSUPPORTED (a company whose provider BUSY writes are not offered for), 409 BUSY_COM_SIGN_IN_UNSUPPORTED (the company signs in to SQL Server with Windows). Plus the shared write refusals (plan, BUSY COM, changed destination, settings, queue) in the operations reference.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","account-optional-field-value-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"6ff6f152-8e6e-b544-ea97-f8343d7a3ab6"}],"id":"580bfc90-8972-41eb-9384-2ea09949a9be","description":"<p><strong>Mutating Cloud Relay operations: these requests can write to BUSY on the enrolled PC.</strong> The four supported routes are <code>/v1/account-create</code>, <code>/v1/account-modify</code>, <code>/v1/product-create</code> and <code>/v1/product-modify</code>. They use the same organization cloud Bearer token as reads, within token/company/subscription scope. A compatible Windows agent is required; an older agent may refuse the operation without writing. Check the actual response instead of assuming this PC always refuses writes.</p>\n<p>Each request requires an <code>Idempotency-Key</code> and the one-send Postman <code>confirmMutating=yes</code> guard. The cloud dispatches a write once and never automatically retries it. After an uncertain or unverified outcome, read the master in BUSY before deciding what to do next. Run these only with deliberate test data; they are not read-only requests.</p>\n","_postman_id":"580bfc90-8972-41eb-9384-2ea09949a9be","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ Voucher Create — WRITES TO BUSY","item":[{"name":"⚠ BUSY sales order – create (writes to BUSY)","id":"1a556569-e9d9-62a7-fbfc-a40955a54497","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-POSTMAN ACC 01\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10 },\n    { \"item\": { \"code\": 1348 }, \"quantity\": 1, \"rate\": 200 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-order-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/sales-order-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)\n<strong>Status (2026-10-23):</strong> deployed and live (release <code>790395a</code>). Windows relays sales orders from source commit <code>6e3f9aa</code> onward with the master writes' rules; an earlier PC version answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>orderReference</code>, <code>date</code>, <code>customer</code>, <code>saleType</code>, <code>materialCenter</code>, <code>lines</code>, <code>lines[].item</code>, <code>lines[].quantity</code>, <code>lines[].rate</code> · <strong>Optional:</strong> <code>voucherSeries</code>, <code>lines[].discountPercent</code> · operation <code>busy.sales-orders.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.</strong> Same operation, body and answer as the Local request <em>Local PC → ⚠ Voucher Create → ⚠ BUSY sales order – create</em>, called through the Cloud Relay with the organization's cloud token. <strong>Create only</strong>: it never changes, cancels or deletes an order. <strong>SQL Server companies with a SQL login, and Access companies</strong> (the PC decides: Windows <code>6c5776d</code> or later accepts Access; an earlier PC answers Access with <code>409 MASTER_WRITE_PROVIDER_UNSUPPORTED</code>). Never run it from scripts or a collection run.</p>\n<p><strong>Body</strong> (at most 64 KiB, else <code>413 REQUEST_TOO_LARGE</code>):</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Required</th>\n<th>Rule</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>companyCode</code>, <code>financialYear</code></td>\n<td>yes</td>\n<td>one company and one year within the token's scope</td>\n</tr>\n<tr>\n<td><code>orderReference</code></td>\n<td>yes</td>\n<td>your own reference, 1-60 characters (trimmed), stored in the order's narration; unique among the company's sales orders of the year (case-insensitive)</td>\n</tr>\n<tr>\n<td><code>date</code></td>\n<td>yes</td>\n<td><code>YYYY-MM-DD</code>, inside the financial year (1 April – 31 March)</td>\n</tr>\n<tr>\n<td><code>customer</code>, <code>saleType</code>, <code>materialCenter</code></td>\n<td>yes</td>\n<td><code>{ \"code\": n }</code> or <code>{ \"name\": \"…\" }</code>, each resolving to exactly one master</td>\n</tr>\n<tr>\n<td><code>voucherSeries</code></td>\n<td>optional</td>\n<td>same form; needed when the company has more than one sales-order series</td>\n</tr>\n<tr>\n<td><code>lines</code></td>\n<td>yes</td>\n<td>1-100 lines</td>\n</tr>\n<tr>\n<td><code>lines[i].item</code></td>\n<td>yes</td>\n<td><code>{ \"code\": n }</code> or <code>{ \"name\": \"…\" }</code></td>\n</tr>\n<tr>\n<td><code>lines[i].quantity</code></td>\n<td>yes</td>\n<td>more than 0, at most 99999999.999, at most 3 decimals (item's main unit)</td>\n</tr>\n<tr>\n<td><code>lines[i].rate</code></td>\n<td>yes</td>\n<td>0 or more, tax-exclusive, at most 2 decimals</td>\n</tr>\n<tr>\n<td><code>lines[i].discountPercent</code></td>\n<td>optional (0)</td>\n<td>0-100, at most 2 decimals</td>\n</tr>\n<tr>\n<td>Manual GST <code>amounts</code>/<code>totals</code>, line <code>description</code>, <code>salesman</code> and <code>queue</code> are accepted (see below); order numbers and any other member are refused. The order's total may not exceed 9999999999.99.</td>\n<td></td>\n<td></td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>2-decimal net-rate rule.</strong> BUSY keeps a sales order's price to 2 decimals, so each line's <code>rate × (100 − discountPercent) / 100</code> must come to at most 2 decimals. Otherwise the cloud refuses the body with <code>400 INVALID_PARAMETER</code>, field <code>lines[i].discountPercent</code>, before anything is sent to the PC — it is never rounded. Example: 150 less 10 % = 135 is accepted; 999.99 less 2 % = 979.9902 is refused. Decimals are judged on the number exactly as written.</p>\n<p><strong>Success (200).</strong> <code>data</code> = <code>{ orderId, orderNumber, orderReference, date, voucherSeries, customer, saleType, taxation (\"local\" | \"central\"), materialCenter, lines: [ { lineNumber, item, unit, quantity, rate, discountPercent, netRate, taxableAmount, cgst, sgst, igst, taxAmount, amount } ], totals { quantity, taxableAmount, taxAmount, amount } }</code>, every value as BUSY stored it (AI Zeny on the PC calculates amounts and GST, half away from zero). <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, outcome (\"created\"), lineCount, verification ([\"busyReadBack\", \"savedRows\"]), elapsedMs, executedAt</code>. The test stores <code>salesOrderId</code>.</p>\n<p><strong>Duplicate reference.</strong> A second order with an <code>orderReference</code> already used that year is refused <code>409 SALES_ORDER_REFERENCE_TAKEN</code> (field <code>orderReference</code>) with <strong><code>metadata.error.details.orderId</code></strong> naming the existing order; nothing is written. This is what makes a deliberate resend safe.</p>\n<p><strong>Idempotency-Key lifecycle (Postman).</strong> The pre-request script mints <code>cloudIdempotencyKey</code> only when none is held (shared with the Cloud master writes). After an <strong>uncertain</strong> outcome — any <code>504</code>, or <code>409 REQUEST_IN_PROGRESS</code> / <code>IDEMPOTENT_REPLAY_UNAVAILABLE</code> / <code>IDEMPOTENCY_KEY_REUSED</code> — the key is <strong>kept</strong>, so an accidental resend carries the same key and the cloud refuses it (<code>409</code>) instead of running it again; a resend with a changed body under the kept key (for example a new reference) is refused <code>409 IDEMPOTENCY_KEY_REUSED</code>. After any definite answer (200, 4xx refusal, 502, 503) it is cleared. The cloud never stores results, so the same key never replays the first answer.</p>\n<p><strong>Uncertain write handling.</strong></p>\n<ul>\n<li><code>504 WRITE_RESULT_UNKNOWN</code> (the PC's answer did not reach AI Zeny; <code>details.reconciliation</code> <code>notChecked</code>) and <code>504 BUSY_WRITE_UNCERTAIN</code> (BUSY stopped while saving; <code>details.reconciliation</code> <code>found</code> + <code>orderId</code>, <code>notFound</code> or <code>notChecked</code>) are <strong>not</strong> successes and <strong>not</strong> failures. Never retry blind and <strong>never with a new reference</strong>.</li>\n<li>First look the order up (Cloud Relay → Registers, Orders &amp; Invoices → Pending sales orders, or BUSY) by <code>orderReference</code>.</li>\n<li>To recover deliberately: unset <code>cloudIdempotencyKey</code>, keep <code>salesOrderReference</code> unchanged, set <code>confirmMutating</code> = <code>yes</code>, send once. If the first send saved, the answer is <code>409 SALES_ORDER_REFERENCE_TAKEN</code> with <code>details.orderId</code> and nothing new is written; otherwise the order is created once.</li>\n<li><code>502 BUSY_WRITE_UNVERIFIED</code>: BUSY <strong>did</strong> save, but its read-back differs (<code>details.orderId</code>, <code>details.mismatchedFields</code>). Check it in BUSY; do not resend.</li>\n<li><code>503 BUSY_COM_QUEUE_TIMEOUT</code>: refused before the job started, nothing written — the only retryable write error.</li>\n<li>The cloud publishes a write once and never retries it; a write lives 400 s and the caller waits up to 405 s: give the request a long timeout.</li>\n</ul>\n<p><strong>Other errors:</strong> 400 <code>BAD_REQUEST</code>, <code>INVALID_PARAMETER</code> (<code>field</code>); 401/403 token or scope; 404 <code>COMPANY_NOT_CONFIGURED</code>; 409 <code>SALES_ORDER_MASTER_CHANGED</code>, <code>MASTER_WRITE_PROVIDER_UNSUPPORTED</code>, <code>BUSY_COM_SIGN_IN_UNSUPPORTED</code>, <code>COMPANY_DISABLED</code>, <code>FINANCIAL_YEAR_NOT_ALLOWED</code>; 413 <code>REQUEST_TOO_LARGE</code>; 422 <code>MASTER_REFERENCE_NOT_FOUND</code>, <code>MASTER_REFERENCE_AMBIGUOUS</code>, <code>SALES_ORDER_SALE_TYPE_UNSUPPORTED</code>, <code>SALES_ORDER_TAX_UNSUPPORTED</code>, <code>BUSY_DATA_INCONSISTENT</code>; 502 <code>BUSY_WRITE_FAILED</code>, <code>DEVICE_ERROR</code>; 503 <code>BUSY_COM_*</code>; 504 <code>BUSY_COM_TIMEOUT</code>.</p>\n<p><strong>Safe test guidance:</strong> only the development-test company (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>) with a <strong>new, unique</strong> <code>salesOrderReference</code> (current value) for each new order — the request is skipped without one. A created test order stays in BUSY. Saved examples are synthetic. Contract: <code>docs/public-api/AI-Zeny-Cloud-API-V1.md</code> (Sales-order create) and the operation reference.</p>\n<p><strong>Durable queue:</strong> optional strict <code>queue</code> (omitted or <code>false</code>: synchronous; <code>true</code>: a <code>202</code> job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.</p>\n<hr />\n<p><strong>Parity update (2026-10-23, deployed in release <code>790395a</code>; the PC must be Windows <code>6c5776d</code> or later for these members).</strong> This request's body sends only the basic members. New optional members and codes:</p>\n<ul>\n<li><code>queue</code> (optional, <code>true</code> or <code>false</code>, default <code>false</code>; <code>null</code> is refused <code>400</code>): with <code>true</code> the PC accepts the write on its durable queue and the answer is <strong><code>202</code></strong> with <code>data: null</code> and <code>metadata.queued: true</code>, <code>metadata.jobId</code> (32 hex), <code>metadata.status</code> — acceptance, <strong>not</strong> a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable <code>companyCode</code>/four-digit <code>financialYear</code>; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (<code>202</code>) and fails there. The cloud sends it once.</li>\n<li>GST modes: <code>taxCalculation</code> (<code>auto</code> default, or <code>manual</code>) and <code>pricingMode</code> (<code>gstExclusive</code> default, or <code>gstInclusive</code>, which must match the voucher type's inclusive flag). Manual needs every line's <code>amounts { taxableAmount, cgst, sgst, igst, amount }</code> and the voucher <code>totals</code> (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: <code>422 GST_AMOUNTS_INVALID</code>, <code>422 GST_MODE_UNSUPPORTED</code>, <code>409 GST_CONFIGURATION_CHANGED</code>.</li>\n<li><code>salesman</code> (optional): <code>{ \"code\": n }</code> or <code>{ \"name\": \"…\" }</code>; omitted or <code>null</code> keeps BUSY's default. Codes: <code>409 SALESMAN_CONFIGURATION_UNSUPPORTED</code>, <code>409 SALESMAN_CONFIGURATION_CHANGED</code>.</li>\n<li>Lines also take <code>description</code> and Manual <code>amounts</code>. Line <code>description</code>: 1-10 positions of at most 40 characters (<code>null</code> or empty keeps a position empty; at least one holds text); the series must allow that many lines (<code>422 DESCRIPTION_LINE_NOT_ALLOWED</code>). <code>422 SALES_ORDER_SERIES_UNSUPPORTED</code>.</li>\n<li>Shared refusals of every write, answered before anything is written: <code>403 PLAN_FEATURE_NOT_INCLUDED</code>, <code>409 PLAN_NOT_KNOWN</code>, <code>503 BUSY_COM_RECOVERY_REQUIRED</code>, <code>409 BUSY_WRITE_TARGET_CHANGED</code>, <code>422 BUSY_SETTING_REQUIRED</code>, <code>502 BUSY_SETTINGS_UNREADABLE</code>; queue refusals <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>, <code>503 WRITE_QUEUE_UNAVAILABLE</code>.</li>\n<li>Write admission (PC from Windows <code>53b556f</code>): <code>409 BUSY_WRITE_REFERENCE_IN_PROGRESS</code> (field <code>orderReference</code>; another write owns this reference — wait for its result, never resend it under another key), <code>409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED</code> (an earlier write with this reference needs review and may have saved — never repost it; look it up by <code>orderReference</code>), <code>503 BUSY_WRITE_ADMISSION_UNAVAILABLE</code> (nothing started). None is retryable; each is a definite answer, so the test clears <code>cloudIdempotencyKey</code>.</li>\n</ul>\n<p>Scenario requests for the new members are in this folder, named <code>⚠ Scenario – …</code> and <code>⚠ EXPECTED REFUSAL …</code>; they are guarded like this one (<code>confirmMutating</code> = <code>yes</code>, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Cloud Relay has not deployed the new numbering schema; these are documentation examples only. Do not Send until Cloud parity is deployed and verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 3,\n      \"rate\": 150,\n      \"discountPercent\": 10\n    },\n    {\n      \"item\": {\n        \"code\": 1348\n      },\n      \"quantity\": 1,\n      \"rate\": 200\n    }\n  ],\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 3,\n      \"rate\": 150,\n      \"discountPercent\": 10\n    },\n    {\n      \"item\": {\n        \"code\": 1348\n      },\n      \"quantity\": 1,\n      \"rate\": 200\n    }\n  ],\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","urlObject":{"path":["v1","sales-order-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"a1c229bd-a99d-6b3c-9f0f-ebfb07d0d019","name":"200 – order created (local GST) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held."}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-POSTMAN ACC 01\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10 },\n    { \"item\": { \"code\": 1348 }, \"quantity\": 1, \"rate\": 200 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-order-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-order-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). Windows relays sales orders from source commit `6e3f9aa` onward with the master writes' rules; an earlier PC version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `orderReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · **Optional:** `voucherSeries`, `lines[].discountPercent` · operation `busy.sales-orders.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales order – create*, called through the Cloud Relay with the organization's cloud token. **Create only**: it never changes, cancels or deletes an order. **SQL Server companies with a SQL login, and Access companies** (the PC decides: Windows `6c5776d` or later accepts Access; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 64 KiB, else `413 REQUEST_TOO_LARGE`):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one year within the token's scope |\n| `orderReference` | yes | your own reference, 1-60 characters (trimmed), stored in the order's narration; unique among the company's sales orders of the year (case-insensitive) |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year (1 April – 31 March) |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`, each resolving to exactly one master |\n| `voucherSeries` | optional | same form; needed when the company has more than one sales-order series |\n| `lines` | yes | 1-100 lines |\n| `lines[i].item` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }` |\n| `lines[i].quantity` | yes | more than 0, at most 99999999.999, at most 3 decimals (item's main unit) |\n| `lines[i].rate` | yes | 0 or more, tax-exclusive, at most 2 decimals |\n| `lines[i].discountPercent` | optional (0) | 0-100, at most 2 decimals |\nManual GST `amounts`/`totals`, line `description`, `salesman` and `queue` are accepted (see below); order numbers and any other member are refused. The order's total may not exceed 9999999999.99.\n\n**2-decimal net-rate rule.** BUSY keeps a sales order's price to 2 decimals, so each line's `rate × (100 − discountPercent) / 100` must come to at most 2 decimals. Otherwise the cloud refuses the body with `400 INVALID_PARAMETER`, field `lines[i].discountPercent`, before anything is sent to the PC — it is never rounded. Example: 150 less 10 % = 135 is accepted; 999.99 less 2 % = 979.9902 is refused. Decimals are judged on the number exactly as written.\n\n**Success (200).** `data` = `{ orderId, orderNumber, orderReference, date, voucherSeries, customer, saleType, taxation (\"local\" | \"central\"), materialCenter, lines: [ { lineNumber, item, unit, quantity, rate, discountPercent, netRate, taxableAmount, cgst, sgst, igst, taxAmount, amount } ], totals { quantity, taxableAmount, taxAmount, amount } }`, every value as BUSY stored it (AI Zeny on the PC calculates amounts and GST, half away from zero). `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, outcome (\"created\"), lineCount, verification ([\"busyReadBack\", \"savedRows\"]), elapsedMs, executedAt`. The test stores `salesOrderId`.\n\n**Duplicate reference.** A second order with an `orderReference` already used that year is refused `409 SALES_ORDER_REFERENCE_TAKEN` (field `orderReference`) with **`metadata.error.details.orderId`** naming the existing order; nothing is written. This is what makes a deliberate resend safe.\n\n**Idempotency-Key lifecycle (Postman).** The pre-request script mints `cloudIdempotencyKey` only when none is held (shared with the Cloud master writes). After an **uncertain** outcome — any `504`, or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED` — the key is **kept**, so an accidental resend carries the same key and the cloud refuses it (`409`) instead of running it again; a resend with a changed body under the kept key (for example a new reference) is refused `409 IDEMPOTENCY_KEY_REUSED`. After any definite answer (200, 4xx refusal, 502, 503) it is cleared. The cloud never stores results, so the same key never replays the first answer.\n\n**Uncertain write handling.**\n- `504 WRITE_RESULT_UNKNOWN` (the PC's answer did not reach AI Zeny; `details.reconciliation` `notChecked`) and `504 BUSY_WRITE_UNCERTAIN` (BUSY stopped while saving; `details.reconciliation` `found` + `orderId`, `notFound` or `notChecked`) are **not** successes and **not** failures. Never retry blind and **never with a new reference**.\n- First look the order up (Cloud Relay → Registers, Orders & Invoices → Pending sales orders, or BUSY) by `orderReference`.\n- To recover deliberately: unset `cloudIdempotencyKey`, keep `salesOrderReference` unchanged, set `confirmMutating` = `yes`, send once. If the first send saved, the answer is `409 SALES_ORDER_REFERENCE_TAKEN` with `details.orderId` and nothing new is written; otherwise the order is created once.\n- `502 BUSY_WRITE_UNVERIFIED`: BUSY **did** save, but its read-back differs (`details.orderId`, `details.mismatchedFields`). Check it in BUSY; do not resend.\n- `503 BUSY_COM_QUEUE_TIMEOUT`: refused before the job started, nothing written — the only retryable write error.\n- The cloud publishes a write once and never retries it; a write lives 400 s and the caller waits up to 405 s: give the request a long timeout.\n\n**Other errors:** 400 `BAD_REQUEST`, `INVALID_PARAMETER` (`field`); 401/403 token or scope; 404 `COMPANY_NOT_CONFIGURED`; 409 `SALES_ORDER_MASTER_CHANGED`, `MASTER_WRITE_PROVIDER_UNSUPPORTED`, `BUSY_COM_SIGN_IN_UNSUPPORTED`, `COMPANY_DISABLED`, `FINANCIAL_YEAR_NOT_ALLOWED`; 413 `REQUEST_TOO_LARGE`; 422 `MASTER_REFERENCE_NOT_FOUND`, `MASTER_REFERENCE_AMBIGUOUS`, `SALES_ORDER_SALE_TYPE_UNSUPPORTED`, `SALES_ORDER_TAX_UNSUPPORTED`, `BUSY_DATA_INCONSISTENT`; 502 `BUSY_WRITE_FAILED`, `DEVICE_ERROR`; 503 `BUSY_COM_*`; 504 `BUSY_COM_TIMEOUT`.\n\n**Safe test guidance:** only the development-test company (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) with a **new, unique** `salesOrderReference` (current value) for each new order — the request is skipped without one. A created test order stays in BUSY. Saved examples are synthetic. Contract: `docs/public-api/AI-Zeny-Cloud-API-V1.md` (Sales-order create) and the operation reference.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- Lines also take `description` and Manual `amounts`. Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_ORDER_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n- Write admission (PC from Windows `53b556f`): `409 BUSY_WRITE_REFERENCE_IN_PROGRESS` (field `orderReference`; another write owns this reference — wait for its result, never resend it under another key), `409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED` (an earlier write with this reference needs review and may have saved — never repost it; look it up by `orderReference`), `503 BUSY_WRITE_ADMISSION_UNAVAILABLE` (nothing started). None is retryable; each is a definite answer, so the test clears `cloudIdempotencyKey`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000001"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"orderId\": 8801,\n    \"orderNumber\": \"SO-25\",\n    \"orderReference\": \"SO-SYNTH-0001\",\n    \"date\": \"2026-10-13\",\n    \"voucherSeries\": { \"code\": 261, \"name\": \"Main\" },\n    \"customer\": { \"code\": 7001, \"name\": \"Synthetic Traders\" },\n    \"saleType\": { \"code\": 1223, \"name\": \"Local-ItemWise\" },\n    \"taxation\": \"local\",\n    \"materialCenter\": { \"code\": 201, \"name\": \"Main Store\" },\n    \"lines\": [\n      { \"lineNumber\": 1, \"item\": { \"code\": 9401, \"name\": \"Synthetic Item\" }, \"unit\": \"Pcs.\", \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10, \"netRate\": 135, \"taxableAmount\": 405, \"cgst\": 24.3, \"sgst\": 24.3, \"igst\": 0, \"taxAmount\": 48.6, \"amount\": 453.6 },\n      { \"lineNumber\": 2, \"item\": { \"code\": 9402, \"name\": \"Synthetic Service\" }, \"unit\": \"Nos.\", \"quantity\": 1, \"rate\": 200, \"discountPercent\": 0, \"netRate\": 200, \"taxableAmount\": 200, \"cgst\": 12, \"sgst\": 12, \"igst\": 0, \"taxAmount\": 24, \"amount\": 224 }\n    ],\n    \"totals\": { \"quantity\": 4, \"taxableAmount\": 605, \"taxAmount\": 72.6, \"amount\": 677.6 }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-orders.create\",\n    \"requestId\": \"rq_0SYNTHET1C0000000000000001\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 2,\n    \"verification\": [\"busyReadBack\", \"savedRows\"],\n    \"elapsedMs\": 5120,\n    \"executedAt\": \"2026-10-13T07:30:00+00:00\"\n  }\n}"},{"id":"ec995469-2598-9872-29ef-05ebfb9ac61a","name":"400 – rate less discount needs more than 2 decimals (refused by the cloud, nothing sent) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held."}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-POSTMAN ACC 01\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10 },\n    { \"item\": { \"code\": 1348 }, \"quantity\": 1, \"rate\": 200 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-order-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-order-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). Windows relays sales orders from source commit `6e3f9aa` onward with the master writes' rules; an earlier PC version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `orderReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · **Optional:** `voucherSeries`, `lines[].discountPercent` · operation `busy.sales-orders.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales order – create*, called through the Cloud Relay with the organization's cloud token. **Create only**: it never changes, cancels or deletes an order. **SQL Server companies with a SQL login, and Access companies** (the PC decides: Windows `6c5776d` or later accepts Access; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 64 KiB, else `413 REQUEST_TOO_LARGE`):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one year within the token's scope |\n| `orderReference` | yes | your own reference, 1-60 characters (trimmed), stored in the order's narration; unique among the company's sales orders of the year (case-insensitive) |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year (1 April – 31 March) |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`, each resolving to exactly one master |\n| `voucherSeries` | optional | same form; needed when the company has more than one sales-order series |\n| `lines` | yes | 1-100 lines |\n| `lines[i].item` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }` |\n| `lines[i].quantity` | yes | more than 0, at most 99999999.999, at most 3 decimals (item's main unit) |\n| `lines[i].rate` | yes | 0 or more, tax-exclusive, at most 2 decimals |\n| `lines[i].discountPercent` | optional (0) | 0-100, at most 2 decimals |\nManual GST `amounts`/`totals`, line `description`, `salesman` and `queue` are accepted (see below); order numbers and any other member are refused. The order's total may not exceed 9999999999.99.\n\n**2-decimal net-rate rule.** BUSY keeps a sales order's price to 2 decimals, so each line's `rate × (100 − discountPercent) / 100` must come to at most 2 decimals. Otherwise the cloud refuses the body with `400 INVALID_PARAMETER`, field `lines[i].discountPercent`, before anything is sent to the PC — it is never rounded. Example: 150 less 10 % = 135 is accepted; 999.99 less 2 % = 979.9902 is refused. Decimals are judged on the number exactly as written.\n\n**Success (200).** `data` = `{ orderId, orderNumber, orderReference, date, voucherSeries, customer, saleType, taxation (\"local\" | \"central\"), materialCenter, lines: [ { lineNumber, item, unit, quantity, rate, discountPercent, netRate, taxableAmount, cgst, sgst, igst, taxAmount, amount } ], totals { quantity, taxableAmount, taxAmount, amount } }`, every value as BUSY stored it (AI Zeny on the PC calculates amounts and GST, half away from zero). `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, outcome (\"created\"), lineCount, verification ([\"busyReadBack\", \"savedRows\"]), elapsedMs, executedAt`. The test stores `salesOrderId`.\n\n**Duplicate reference.** A second order with an `orderReference` already used that year is refused `409 SALES_ORDER_REFERENCE_TAKEN` (field `orderReference`) with **`metadata.error.details.orderId`** naming the existing order; nothing is written. This is what makes a deliberate resend safe.\n\n**Idempotency-Key lifecycle (Postman).** The pre-request script mints `cloudIdempotencyKey` only when none is held (shared with the Cloud master writes). After an **uncertain** outcome — any `504`, or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED` — the key is **kept**, so an accidental resend carries the same key and the cloud refuses it (`409`) instead of running it again; a resend with a changed body under the kept key (for example a new reference) is refused `409 IDEMPOTENCY_KEY_REUSED`. After any definite answer (200, 4xx refusal, 502, 503) it is cleared. The cloud never stores results, so the same key never replays the first answer.\n\n**Uncertain write handling.**\n- `504 WRITE_RESULT_UNKNOWN` (the PC's answer did not reach AI Zeny; `details.reconciliation` `notChecked`) and `504 BUSY_WRITE_UNCERTAIN` (BUSY stopped while saving; `details.reconciliation` `found` + `orderId`, `notFound` or `notChecked`) are **not** successes and **not** failures. Never retry blind and **never with a new reference**.\n- First look the order up (Cloud Relay → Registers, Orders & Invoices → Pending sales orders, or BUSY) by `orderReference`.\n- To recover deliberately: unset `cloudIdempotencyKey`, keep `salesOrderReference` unchanged, set `confirmMutating` = `yes`, send once. If the first send saved, the answer is `409 SALES_ORDER_REFERENCE_TAKEN` with `details.orderId` and nothing new is written; otherwise the order is created once.\n- `502 BUSY_WRITE_UNVERIFIED`: BUSY **did** save, but its read-back differs (`details.orderId`, `details.mismatchedFields`). Check it in BUSY; do not resend.\n- `503 BUSY_COM_QUEUE_TIMEOUT`: refused before the job started, nothing written — the only retryable write error.\n- The cloud publishes a write once and never retries it; a write lives 400 s and the caller waits up to 405 s: give the request a long timeout.\n\n**Other errors:** 400 `BAD_REQUEST`, `INVALID_PARAMETER` (`field`); 401/403 token or scope; 404 `COMPANY_NOT_CONFIGURED`; 409 `SALES_ORDER_MASTER_CHANGED`, `MASTER_WRITE_PROVIDER_UNSUPPORTED`, `BUSY_COM_SIGN_IN_UNSUPPORTED`, `COMPANY_DISABLED`, `FINANCIAL_YEAR_NOT_ALLOWED`; 413 `REQUEST_TOO_LARGE`; 422 `MASTER_REFERENCE_NOT_FOUND`, `MASTER_REFERENCE_AMBIGUOUS`, `SALES_ORDER_SALE_TYPE_UNSUPPORTED`, `SALES_ORDER_TAX_UNSUPPORTED`, `BUSY_DATA_INCONSISTENT`; 502 `BUSY_WRITE_FAILED`, `DEVICE_ERROR`; 503 `BUSY_COM_*`; 504 `BUSY_COM_TIMEOUT`.\n\n**Safe test guidance:** only the development-test company (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) with a **new, unique** `salesOrderReference` (current value) for each new order — the request is skipped without one. A created test order stays in BUSY. Saved examples are synthetic. Contract: `docs/public-api/AI-Zeny-Cloud-API-V1.md` (Sales-order create) and the operation reference.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- Lines also take `description` and Manual `amounts`. Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_ORDER_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n- Write admission (PC from Windows `53b556f`): `409 BUSY_WRITE_REFERENCE_IN_PROGRESS` (field `orderReference`; another write owns this reference — wait for its result, never resend it under another key), `409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED` (an earlier write with this reference needs review and may have saved — never repost it; look it up by `orderReference`), `503 BUSY_WRITE_ADMISSION_UNAVAILABLE` (nothing started). None is retryable; each is a definite answer, so the test clears `cloudIdempotencyKey`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"lines[0]: the rate less discountPercent must come to at most 2 decimals (BUSY keeps the price to 2 decimals).\",\n      \"field\": \"lines[0].discountPercent\"\n    },\n    \"requestId\": \"req_0SYNTHET1C0000000000000002\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"123bd312-54b2-0024-5f42-4007cea14a98","name":"409 – duplicate orderReference (details.orderId; nothing written) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held."}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-POSTMAN ACC 01\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10 },\n    { \"item\": { \"code\": 1348 }, \"quantity\": 1, \"rate\": 200 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-order-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-order-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). Windows relays sales orders from source commit `6e3f9aa` onward with the master writes' rules; an earlier PC version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `orderReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · **Optional:** `voucherSeries`, `lines[].discountPercent` · operation `busy.sales-orders.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales order – create*, called through the Cloud Relay with the organization's cloud token. **Create only**: it never changes, cancels or deletes an order. **SQL Server companies with a SQL login, and Access companies** (the PC decides: Windows `6c5776d` or later accepts Access; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 64 KiB, else `413 REQUEST_TOO_LARGE`):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one year within the token's scope |\n| `orderReference` | yes | your own reference, 1-60 characters (trimmed), stored in the order's narration; unique among the company's sales orders of the year (case-insensitive) |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year (1 April – 31 March) |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`, each resolving to exactly one master |\n| `voucherSeries` | optional | same form; needed when the company has more than one sales-order series |\n| `lines` | yes | 1-100 lines |\n| `lines[i].item` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }` |\n| `lines[i].quantity` | yes | more than 0, at most 99999999.999, at most 3 decimals (item's main unit) |\n| `lines[i].rate` | yes | 0 or more, tax-exclusive, at most 2 decimals |\n| `lines[i].discountPercent` | optional (0) | 0-100, at most 2 decimals |\nManual GST `amounts`/`totals`, line `description`, `salesman` and `queue` are accepted (see below); order numbers and any other member are refused. The order's total may not exceed 9999999999.99.\n\n**2-decimal net-rate rule.** BUSY keeps a sales order's price to 2 decimals, so each line's `rate × (100 − discountPercent) / 100` must come to at most 2 decimals. Otherwise the cloud refuses the body with `400 INVALID_PARAMETER`, field `lines[i].discountPercent`, before anything is sent to the PC — it is never rounded. Example: 150 less 10 % = 135 is accepted; 999.99 less 2 % = 979.9902 is refused. Decimals are judged on the number exactly as written.\n\n**Success (200).** `data` = `{ orderId, orderNumber, orderReference, date, voucherSeries, customer, saleType, taxation (\"local\" | \"central\"), materialCenter, lines: [ { lineNumber, item, unit, quantity, rate, discountPercent, netRate, taxableAmount, cgst, sgst, igst, taxAmount, amount } ], totals { quantity, taxableAmount, taxAmount, amount } }`, every value as BUSY stored it (AI Zeny on the PC calculates amounts and GST, half away from zero). `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, outcome (\"created\"), lineCount, verification ([\"busyReadBack\", \"savedRows\"]), elapsedMs, executedAt`. The test stores `salesOrderId`.\n\n**Duplicate reference.** A second order with an `orderReference` already used that year is refused `409 SALES_ORDER_REFERENCE_TAKEN` (field `orderReference`) with **`metadata.error.details.orderId`** naming the existing order; nothing is written. This is what makes a deliberate resend safe.\n\n**Idempotency-Key lifecycle (Postman).** The pre-request script mints `cloudIdempotencyKey` only when none is held (shared with the Cloud master writes). After an **uncertain** outcome — any `504`, or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED` — the key is **kept**, so an accidental resend carries the same key and the cloud refuses it (`409`) instead of running it again; a resend with a changed body under the kept key (for example a new reference) is refused `409 IDEMPOTENCY_KEY_REUSED`. After any definite answer (200, 4xx refusal, 502, 503) it is cleared. The cloud never stores results, so the same key never replays the first answer.\n\n**Uncertain write handling.**\n- `504 WRITE_RESULT_UNKNOWN` (the PC's answer did not reach AI Zeny; `details.reconciliation` `notChecked`) and `504 BUSY_WRITE_UNCERTAIN` (BUSY stopped while saving; `details.reconciliation` `found` + `orderId`, `notFound` or `notChecked`) are **not** successes and **not** failures. Never retry blind and **never with a new reference**.\n- First look the order up (Cloud Relay → Registers, Orders & Invoices → Pending sales orders, or BUSY) by `orderReference`.\n- To recover deliberately: unset `cloudIdempotencyKey`, keep `salesOrderReference` unchanged, set `confirmMutating` = `yes`, send once. If the first send saved, the answer is `409 SALES_ORDER_REFERENCE_TAKEN` with `details.orderId` and nothing new is written; otherwise the order is created once.\n- `502 BUSY_WRITE_UNVERIFIED`: BUSY **did** save, but its read-back differs (`details.orderId`, `details.mismatchedFields`). Check it in BUSY; do not resend.\n- `503 BUSY_COM_QUEUE_TIMEOUT`: refused before the job started, nothing written — the only retryable write error.\n- The cloud publishes a write once and never retries it; a write lives 400 s and the caller waits up to 405 s: give the request a long timeout.\n\n**Other errors:** 400 `BAD_REQUEST`, `INVALID_PARAMETER` (`field`); 401/403 token or scope; 404 `COMPANY_NOT_CONFIGURED`; 409 `SALES_ORDER_MASTER_CHANGED`, `MASTER_WRITE_PROVIDER_UNSUPPORTED`, `BUSY_COM_SIGN_IN_UNSUPPORTED`, `COMPANY_DISABLED`, `FINANCIAL_YEAR_NOT_ALLOWED`; 413 `REQUEST_TOO_LARGE`; 422 `MASTER_REFERENCE_NOT_FOUND`, `MASTER_REFERENCE_AMBIGUOUS`, `SALES_ORDER_SALE_TYPE_UNSUPPORTED`, `SALES_ORDER_TAX_UNSUPPORTED`, `BUSY_DATA_INCONSISTENT`; 502 `BUSY_WRITE_FAILED`, `DEVICE_ERROR`; 503 `BUSY_COM_*`; 504 `BUSY_COM_TIMEOUT`.\n\n**Safe test guidance:** only the development-test company (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) with a **new, unique** `salesOrderReference` (current value) for each new order — the request is skipped without one. A created test order stays in BUSY. Saved examples are synthetic. Contract: `docs/public-api/AI-Zeny-Cloud-API-V1.md` (Sales-order create) and the operation reference.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- Lines also take `description` and Manual `amounts`. Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_ORDER_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n- Write admission (PC from Windows `53b556f`): `409 BUSY_WRITE_REFERENCE_IN_PROGRESS` (field `orderReference`; another write owns this reference — wait for its result, never resend it under another key), `409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED` (an earlier write with this reference needs review and may have saved — never repost it; look it up by `orderReference`), `503 BUSY_WRITE_ADMISSION_UNAVAILABLE` (nothing started). None is retryable; each is a definite answer, so the test clears `cloudIdempotencyKey`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000003"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SALES_ORDER_REFERENCE_TAKEN\",\n      \"message\": \"A sales order of this company and financial year already holds this orderReference. A create never changes an existing order; if your earlier call saved it, metadata.error.details.orderId names it.\",\n      \"field\": \"orderReference\",\n      \"details\": { \"orderId\": 8801 }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000003\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"9f479f06-f42b-57a2-1105-ab27ffcbb910","name":"504 – WRITE_RESULT_UNKNOWN (PC's answer lost): key kept, do not resend blind [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held."}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-POSTMAN ACC 01\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10 },\n    { \"item\": { \"code\": 1348 }, \"quantity\": 1, \"rate\": 200 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-order-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-order-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). Windows relays sales orders from source commit `6e3f9aa` onward with the master writes' rules; an earlier PC version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `orderReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · **Optional:** `voucherSeries`, `lines[].discountPercent` · operation `busy.sales-orders.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales order – create*, called through the Cloud Relay with the organization's cloud token. **Create only**: it never changes, cancels or deletes an order. **SQL Server companies with a SQL login, and Access companies** (the PC decides: Windows `6c5776d` or later accepts Access; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 64 KiB, else `413 REQUEST_TOO_LARGE`):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one year within the token's scope |\n| `orderReference` | yes | your own reference, 1-60 characters (trimmed), stored in the order's narration; unique among the company's sales orders of the year (case-insensitive) |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year (1 April – 31 March) |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`, each resolving to exactly one master |\n| `voucherSeries` | optional | same form; needed when the company has more than one sales-order series |\n| `lines` | yes | 1-100 lines |\n| `lines[i].item` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }` |\n| `lines[i].quantity` | yes | more than 0, at most 99999999.999, at most 3 decimals (item's main unit) |\n| `lines[i].rate` | yes | 0 or more, tax-exclusive, at most 2 decimals |\n| `lines[i].discountPercent` | optional (0) | 0-100, at most 2 decimals |\nManual GST `amounts`/`totals`, line `description`, `salesman` and `queue` are accepted (see below); order numbers and any other member are refused. The order's total may not exceed 9999999999.99.\n\n**2-decimal net-rate rule.** BUSY keeps a sales order's price to 2 decimals, so each line's `rate × (100 − discountPercent) / 100` must come to at most 2 decimals. Otherwise the cloud refuses the body with `400 INVALID_PARAMETER`, field `lines[i].discountPercent`, before anything is sent to the PC — it is never rounded. Example: 150 less 10 % = 135 is accepted; 999.99 less 2 % = 979.9902 is refused. Decimals are judged on the number exactly as written.\n\n**Success (200).** `data` = `{ orderId, orderNumber, orderReference, date, voucherSeries, customer, saleType, taxation (\"local\" | \"central\"), materialCenter, lines: [ { lineNumber, item, unit, quantity, rate, discountPercent, netRate, taxableAmount, cgst, sgst, igst, taxAmount, amount } ], totals { quantity, taxableAmount, taxAmount, amount } }`, every value as BUSY stored it (AI Zeny on the PC calculates amounts and GST, half away from zero). `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, outcome (\"created\"), lineCount, verification ([\"busyReadBack\", \"savedRows\"]), elapsedMs, executedAt`. The test stores `salesOrderId`.\n\n**Duplicate reference.** A second order with an `orderReference` already used that year is refused `409 SALES_ORDER_REFERENCE_TAKEN` (field `orderReference`) with **`metadata.error.details.orderId`** naming the existing order; nothing is written. This is what makes a deliberate resend safe.\n\n**Idempotency-Key lifecycle (Postman).** The pre-request script mints `cloudIdempotencyKey` only when none is held (shared with the Cloud master writes). After an **uncertain** outcome — any `504`, or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED` — the key is **kept**, so an accidental resend carries the same key and the cloud refuses it (`409`) instead of running it again; a resend with a changed body under the kept key (for example a new reference) is refused `409 IDEMPOTENCY_KEY_REUSED`. After any definite answer (200, 4xx refusal, 502, 503) it is cleared. The cloud never stores results, so the same key never replays the first answer.\n\n**Uncertain write handling.**\n- `504 WRITE_RESULT_UNKNOWN` (the PC's answer did not reach AI Zeny; `details.reconciliation` `notChecked`) and `504 BUSY_WRITE_UNCERTAIN` (BUSY stopped while saving; `details.reconciliation` `found` + `orderId`, `notFound` or `notChecked`) are **not** successes and **not** failures. Never retry blind and **never with a new reference**.\n- First look the order up (Cloud Relay → Registers, Orders & Invoices → Pending sales orders, or BUSY) by `orderReference`.\n- To recover deliberately: unset `cloudIdempotencyKey`, keep `salesOrderReference` unchanged, set `confirmMutating` = `yes`, send once. If the first send saved, the answer is `409 SALES_ORDER_REFERENCE_TAKEN` with `details.orderId` and nothing new is written; otherwise the order is created once.\n- `502 BUSY_WRITE_UNVERIFIED`: BUSY **did** save, but its read-back differs (`details.orderId`, `details.mismatchedFields`). Check it in BUSY; do not resend.\n- `503 BUSY_COM_QUEUE_TIMEOUT`: refused before the job started, nothing written — the only retryable write error.\n- The cloud publishes a write once and never retries it; a write lives 400 s and the caller waits up to 405 s: give the request a long timeout.\n\n**Other errors:** 400 `BAD_REQUEST`, `INVALID_PARAMETER` (`field`); 401/403 token or scope; 404 `COMPANY_NOT_CONFIGURED`; 409 `SALES_ORDER_MASTER_CHANGED`, `MASTER_WRITE_PROVIDER_UNSUPPORTED`, `BUSY_COM_SIGN_IN_UNSUPPORTED`, `COMPANY_DISABLED`, `FINANCIAL_YEAR_NOT_ALLOWED`; 413 `REQUEST_TOO_LARGE`; 422 `MASTER_REFERENCE_NOT_FOUND`, `MASTER_REFERENCE_AMBIGUOUS`, `SALES_ORDER_SALE_TYPE_UNSUPPORTED`, `SALES_ORDER_TAX_UNSUPPORTED`, `BUSY_DATA_INCONSISTENT`; 502 `BUSY_WRITE_FAILED`, `DEVICE_ERROR`; 503 `BUSY_COM_*`; 504 `BUSY_COM_TIMEOUT`.\n\n**Safe test guidance:** only the development-test company (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) with a **new, unique** `salesOrderReference` (current value) for each new order — the request is skipped without one. A created test order stays in BUSY. Saved examples are synthetic. Contract: `docs/public-api/AI-Zeny-Cloud-API-V1.md` (Sales-order create) and the operation reference.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- Lines also take `description` and Manual `amounts`. Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_ORDER_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n- Write admission (PC from Windows `53b556f`): `409 BUSY_WRITE_REFERENCE_IN_PROGRESS` (field `orderReference`; another write owns this reference — wait for its result, never resend it under another key), `409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED` (an earlier write with this reference needs review and may have saved — never repost it; look it up by `orderReference`), `503 BUSY_WRITE_ADMISSION_UNAVAILABLE` (nothing started). None is retryable; each is a definite answer, so the test clears `cloudIdempotencyKey`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000004","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"WRITE_RESULT_UNKNOWN\",\n      \"message\": \"The PC's answer to this sales order did not reach AI Zeny, so whether BUSY saved it is not known. Look the order up by its orderReference before trying again; a retry with the same orderReference is refused if the first one saved (409 SALES_ORDER_REFERENCE_TAKEN with details.orderId).\",\n      \"details\": { \"reconciliation\": \"notChecked\" }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000004\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"0100f711-8580-7578-62b3-a505303d52fb","name":"504 – BUSY_WRITE_UNCERTAIN, reconciled found: key kept, do not resend [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held."}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-POSTMAN ACC 01\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10 },\n    { \"item\": { \"code\": 1348 }, \"quantity\": 1, \"rate\": 200 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-order-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-order-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). Windows relays sales orders from source commit `6e3f9aa` onward with the master writes' rules; an earlier PC version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `orderReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · **Optional:** `voucherSeries`, `lines[].discountPercent` · operation `busy.sales-orders.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales order – create*, called through the Cloud Relay with the organization's cloud token. **Create only**: it never changes, cancels or deletes an order. **SQL Server companies with a SQL login, and Access companies** (the PC decides: Windows `6c5776d` or later accepts Access; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 64 KiB, else `413 REQUEST_TOO_LARGE`):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one year within the token's scope |\n| `orderReference` | yes | your own reference, 1-60 characters (trimmed), stored in the order's narration; unique among the company's sales orders of the year (case-insensitive) |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year (1 April – 31 March) |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`, each resolving to exactly one master |\n| `voucherSeries` | optional | same form; needed when the company has more than one sales-order series |\n| `lines` | yes | 1-100 lines |\n| `lines[i].item` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }` |\n| `lines[i].quantity` | yes | more than 0, at most 99999999.999, at most 3 decimals (item's main unit) |\n| `lines[i].rate` | yes | 0 or more, tax-exclusive, at most 2 decimals |\n| `lines[i].discountPercent` | optional (0) | 0-100, at most 2 decimals |\nManual GST `amounts`/`totals`, line `description`, `salesman` and `queue` are accepted (see below); order numbers and any other member are refused. The order's total may not exceed 9999999999.99.\n\n**2-decimal net-rate rule.** BUSY keeps a sales order's price to 2 decimals, so each line's `rate × (100 − discountPercent) / 100` must come to at most 2 decimals. Otherwise the cloud refuses the body with `400 INVALID_PARAMETER`, field `lines[i].discountPercent`, before anything is sent to the PC — it is never rounded. Example: 150 less 10 % = 135 is accepted; 999.99 less 2 % = 979.9902 is refused. Decimals are judged on the number exactly as written.\n\n**Success (200).** `data` = `{ orderId, orderNumber, orderReference, date, voucherSeries, customer, saleType, taxation (\"local\" | \"central\"), materialCenter, lines: [ { lineNumber, item, unit, quantity, rate, discountPercent, netRate, taxableAmount, cgst, sgst, igst, taxAmount, amount } ], totals { quantity, taxableAmount, taxAmount, amount } }`, every value as BUSY stored it (AI Zeny on the PC calculates amounts and GST, half away from zero). `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, outcome (\"created\"), lineCount, verification ([\"busyReadBack\", \"savedRows\"]), elapsedMs, executedAt`. The test stores `salesOrderId`.\n\n**Duplicate reference.** A second order with an `orderReference` already used that year is refused `409 SALES_ORDER_REFERENCE_TAKEN` (field `orderReference`) with **`metadata.error.details.orderId`** naming the existing order; nothing is written. This is what makes a deliberate resend safe.\n\n**Idempotency-Key lifecycle (Postman).** The pre-request script mints `cloudIdempotencyKey` only when none is held (shared with the Cloud master writes). After an **uncertain** outcome — any `504`, or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED` — the key is **kept**, so an accidental resend carries the same key and the cloud refuses it (`409`) instead of running it again; a resend with a changed body under the kept key (for example a new reference) is refused `409 IDEMPOTENCY_KEY_REUSED`. After any definite answer (200, 4xx refusal, 502, 503) it is cleared. The cloud never stores results, so the same key never replays the first answer.\n\n**Uncertain write handling.**\n- `504 WRITE_RESULT_UNKNOWN` (the PC's answer did not reach AI Zeny; `details.reconciliation` `notChecked`) and `504 BUSY_WRITE_UNCERTAIN` (BUSY stopped while saving; `details.reconciliation` `found` + `orderId`, `notFound` or `notChecked`) are **not** successes and **not** failures. Never retry blind and **never with a new reference**.\n- First look the order up (Cloud Relay → Registers, Orders & Invoices → Pending sales orders, or BUSY) by `orderReference`.\n- To recover deliberately: unset `cloudIdempotencyKey`, keep `salesOrderReference` unchanged, set `confirmMutating` = `yes`, send once. If the first send saved, the answer is `409 SALES_ORDER_REFERENCE_TAKEN` with `details.orderId` and nothing new is written; otherwise the order is created once.\n- `502 BUSY_WRITE_UNVERIFIED`: BUSY **did** save, but its read-back differs (`details.orderId`, `details.mismatchedFields`). Check it in BUSY; do not resend.\n- `503 BUSY_COM_QUEUE_TIMEOUT`: refused before the job started, nothing written — the only retryable write error.\n- The cloud publishes a write once and never retries it; a write lives 400 s and the caller waits up to 405 s: give the request a long timeout.\n\n**Other errors:** 400 `BAD_REQUEST`, `INVALID_PARAMETER` (`field`); 401/403 token or scope; 404 `COMPANY_NOT_CONFIGURED`; 409 `SALES_ORDER_MASTER_CHANGED`, `MASTER_WRITE_PROVIDER_UNSUPPORTED`, `BUSY_COM_SIGN_IN_UNSUPPORTED`, `COMPANY_DISABLED`, `FINANCIAL_YEAR_NOT_ALLOWED`; 413 `REQUEST_TOO_LARGE`; 422 `MASTER_REFERENCE_NOT_FOUND`, `MASTER_REFERENCE_AMBIGUOUS`, `SALES_ORDER_SALE_TYPE_UNSUPPORTED`, `SALES_ORDER_TAX_UNSUPPORTED`, `BUSY_DATA_INCONSISTENT`; 502 `BUSY_WRITE_FAILED`, `DEVICE_ERROR`; 503 `BUSY_COM_*`; 504 `BUSY_COM_TIMEOUT`.\n\n**Safe test guidance:** only the development-test company (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) with a **new, unique** `salesOrderReference` (current value) for each new order — the request is skipped without one. A created test order stays in BUSY. Saved examples are synthetic. Contract: `docs/public-api/AI-Zeny-Cloud-API-V1.md` (Sales-order create) and the operation reference.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- Lines also take `description` and Manual `amounts`. Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_ORDER_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n- Write admission (PC from Windows `53b556f`): `409 BUSY_WRITE_REFERENCE_IN_PROGRESS` (field `orderReference`; another write owns this reference — wait for its result, never resend it under another key), `409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED` (an earlier write with this reference needs review and may have saved — never repost it; look it up by `orderReference`), `503 BUSY_WRITE_ADMISSION_UNAVAILABLE` (nothing started). None is retryable; each is a definite answer, so the test clears `cloudIdempotencyKey`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000005"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"BUSY stopped while saving the sales order; a sales order with this orderReference exists now (metadata.error.details.orderId). Check it in BUSY; do not send it again.\",\n      \"details\": { \"orderId\": 8802, \"reconciliation\": \"found\" }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000005\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"1129f81f-477a-a9df-1c2a-4d50c6f58be4","name":"409 – accidental resend with the kept key (IDEMPOTENT_REPLAY_UNAVAILABLE; not run again) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held."}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-POSTMAN ACC 01\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10 },\n    { \"item\": { \"code\": 1348 }, \"quantity\": 1, \"rate\": 200 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-order-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-order-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). Windows relays sales orders from source commit `6e3f9aa` onward with the master writes' rules; an earlier PC version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `orderReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · **Optional:** `voucherSeries`, `lines[].discountPercent` · operation `busy.sales-orders.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales order – create*, called through the Cloud Relay with the organization's cloud token. **Create only**: it never changes, cancels or deletes an order. **SQL Server companies with a SQL login, and Access companies** (the PC decides: Windows `6c5776d` or later accepts Access; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 64 KiB, else `413 REQUEST_TOO_LARGE`):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one year within the token's scope |\n| `orderReference` | yes | your own reference, 1-60 characters (trimmed), stored in the order's narration; unique among the company's sales orders of the year (case-insensitive) |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year (1 April – 31 March) |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`, each resolving to exactly one master |\n| `voucherSeries` | optional | same form; needed when the company has more than one sales-order series |\n| `lines` | yes | 1-100 lines |\n| `lines[i].item` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }` |\n| `lines[i].quantity` | yes | more than 0, at most 99999999.999, at most 3 decimals (item's main unit) |\n| `lines[i].rate` | yes | 0 or more, tax-exclusive, at most 2 decimals |\n| `lines[i].discountPercent` | optional (0) | 0-100, at most 2 decimals |\nManual GST `amounts`/`totals`, line `description`, `salesman` and `queue` are accepted (see below); order numbers and any other member are refused. The order's total may not exceed 9999999999.99.\n\n**2-decimal net-rate rule.** BUSY keeps a sales order's price to 2 decimals, so each line's `rate × (100 − discountPercent) / 100` must come to at most 2 decimals. Otherwise the cloud refuses the body with `400 INVALID_PARAMETER`, field `lines[i].discountPercent`, before anything is sent to the PC — it is never rounded. Example: 150 less 10 % = 135 is accepted; 999.99 less 2 % = 979.9902 is refused. Decimals are judged on the number exactly as written.\n\n**Success (200).** `data` = `{ orderId, orderNumber, orderReference, date, voucherSeries, customer, saleType, taxation (\"local\" | \"central\"), materialCenter, lines: [ { lineNumber, item, unit, quantity, rate, discountPercent, netRate, taxableAmount, cgst, sgst, igst, taxAmount, amount } ], totals { quantity, taxableAmount, taxAmount, amount } }`, every value as BUSY stored it (AI Zeny on the PC calculates amounts and GST, half away from zero). `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, outcome (\"created\"), lineCount, verification ([\"busyReadBack\", \"savedRows\"]), elapsedMs, executedAt`. The test stores `salesOrderId`.\n\n**Duplicate reference.** A second order with an `orderReference` already used that year is refused `409 SALES_ORDER_REFERENCE_TAKEN` (field `orderReference`) with **`metadata.error.details.orderId`** naming the existing order; nothing is written. This is what makes a deliberate resend safe.\n\n**Idempotency-Key lifecycle (Postman).** The pre-request script mints `cloudIdempotencyKey` only when none is held (shared with the Cloud master writes). After an **uncertain** outcome — any `504`, or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED` — the key is **kept**, so an accidental resend carries the same key and the cloud refuses it (`409`) instead of running it again; a resend with a changed body under the kept key (for example a new reference) is refused `409 IDEMPOTENCY_KEY_REUSED`. After any definite answer (200, 4xx refusal, 502, 503) it is cleared. The cloud never stores results, so the same key never replays the first answer.\n\n**Uncertain write handling.**\n- `504 WRITE_RESULT_UNKNOWN` (the PC's answer did not reach AI Zeny; `details.reconciliation` `notChecked`) and `504 BUSY_WRITE_UNCERTAIN` (BUSY stopped while saving; `details.reconciliation` `found` + `orderId`, `notFound` or `notChecked`) are **not** successes and **not** failures. Never retry blind and **never with a new reference**.\n- First look the order up (Cloud Relay → Registers, Orders & Invoices → Pending sales orders, or BUSY) by `orderReference`.\n- To recover deliberately: unset `cloudIdempotencyKey`, keep `salesOrderReference` unchanged, set `confirmMutating` = `yes`, send once. If the first send saved, the answer is `409 SALES_ORDER_REFERENCE_TAKEN` with `details.orderId` and nothing new is written; otherwise the order is created once.\n- `502 BUSY_WRITE_UNVERIFIED`: BUSY **did** save, but its read-back differs (`details.orderId`, `details.mismatchedFields`). Check it in BUSY; do not resend.\n- `503 BUSY_COM_QUEUE_TIMEOUT`: refused before the job started, nothing written — the only retryable write error.\n- The cloud publishes a write once and never retries it; a write lives 400 s and the caller waits up to 405 s: give the request a long timeout.\n\n**Other errors:** 400 `BAD_REQUEST`, `INVALID_PARAMETER` (`field`); 401/403 token or scope; 404 `COMPANY_NOT_CONFIGURED`; 409 `SALES_ORDER_MASTER_CHANGED`, `MASTER_WRITE_PROVIDER_UNSUPPORTED`, `BUSY_COM_SIGN_IN_UNSUPPORTED`, `COMPANY_DISABLED`, `FINANCIAL_YEAR_NOT_ALLOWED`; 413 `REQUEST_TOO_LARGE`; 422 `MASTER_REFERENCE_NOT_FOUND`, `MASTER_REFERENCE_AMBIGUOUS`, `SALES_ORDER_SALE_TYPE_UNSUPPORTED`, `SALES_ORDER_TAX_UNSUPPORTED`, `BUSY_DATA_INCONSISTENT`; 502 `BUSY_WRITE_FAILED`, `DEVICE_ERROR`; 503 `BUSY_COM_*`; 504 `BUSY_COM_TIMEOUT`.\n\n**Safe test guidance:** only the development-test company (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) with a **new, unique** `salesOrderReference` (current value) for each new order — the request is skipped without one. A created test order stays in BUSY. Saved examples are synthetic. Contract: `docs/public-api/AI-Zeny-Cloud-API-V1.md` (Sales-order create) and the operation reference.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- Lines also take `description` and Manual `amounts`. Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_ORDER_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n- Write admission (PC from Windows `53b556f`): `409 BUSY_WRITE_REFERENCE_IN_PROGRESS` (field `orderReference`; another write owns this reference — wait for its result, never resend it under another key), `409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED` (an earlier write with this reference needs review and may have saved — never repost it; look it up by `orderReference`), `503 BUSY_WRITE_ADMISSION_UNAVAILABLE` (nothing started). None is retryable; each is a definite answer, so the test clears `cloudIdempotencyKey`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"IDEMPOTENT_REPLAY_UNAVAILABLE\",\n      \"message\": \"That request already finished. Results are never stored, so it cannot be replayed.\",\n      \"details\": { \"requestId\": \"rq_0SYNTHET1C0000000000000004\", \"status\": \"unknown\" }\n    },\n    \"requestId\": \"req_0SYNTHET1C0000000000000006\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"2da95bcd-54ad-db90-c159-a2e31e9bc647","name":"502 – BUSY_WRITE_UNVERIFIED (saved, read-back differs; do not resend) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held."}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-POSTMAN ACC 01\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 3, \"rate\": 150, \"discountPercent\": 10 },\n    { \"item\": { \"code\": 1348 }, \"quantity\": 1, \"rate\": 200 }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-order-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-order-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). Windows relays sales orders from source commit `6e3f9aa` onward with the master writes' rules; an earlier PC version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `orderReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · **Optional:** `voucherSeries`, `lines[].discountPercent` · operation `busy.sales-orders.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales order – create*, called through the Cloud Relay with the organization's cloud token. **Create only**: it never changes, cancels or deletes an order. **SQL Server companies with a SQL login, and Access companies** (the PC decides: Windows `6c5776d` or later accepts Access; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 64 KiB, else `413 REQUEST_TOO_LARGE`):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one year within the token's scope |\n| `orderReference` | yes | your own reference, 1-60 characters (trimmed), stored in the order's narration; unique among the company's sales orders of the year (case-insensitive) |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year (1 April – 31 March) |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`, each resolving to exactly one master |\n| `voucherSeries` | optional | same form; needed when the company has more than one sales-order series |\n| `lines` | yes | 1-100 lines |\n| `lines[i].item` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }` |\n| `lines[i].quantity` | yes | more than 0, at most 99999999.999, at most 3 decimals (item's main unit) |\n| `lines[i].rate` | yes | 0 or more, tax-exclusive, at most 2 decimals |\n| `lines[i].discountPercent` | optional (0) | 0-100, at most 2 decimals |\nManual GST `amounts`/`totals`, line `description`, `salesman` and `queue` are accepted (see below); order numbers and any other member are refused. The order's total may not exceed 9999999999.99.\n\n**2-decimal net-rate rule.** BUSY keeps a sales order's price to 2 decimals, so each line's `rate × (100 − discountPercent) / 100` must come to at most 2 decimals. Otherwise the cloud refuses the body with `400 INVALID_PARAMETER`, field `lines[i].discountPercent`, before anything is sent to the PC — it is never rounded. Example: 150 less 10 % = 135 is accepted; 999.99 less 2 % = 979.9902 is refused. Decimals are judged on the number exactly as written.\n\n**Success (200).** `data` = `{ orderId, orderNumber, orderReference, date, voucherSeries, customer, saleType, taxation (\"local\" | \"central\"), materialCenter, lines: [ { lineNumber, item, unit, quantity, rate, discountPercent, netRate, taxableAmount, cgst, sgst, igst, taxAmount, amount } ], totals { quantity, taxableAmount, taxAmount, amount } }`, every value as BUSY stored it (AI Zeny on the PC calculates amounts and GST, half away from zero). `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, outcome (\"created\"), lineCount, verification ([\"busyReadBack\", \"savedRows\"]), elapsedMs, executedAt`. The test stores `salesOrderId`.\n\n**Duplicate reference.** A second order with an `orderReference` already used that year is refused `409 SALES_ORDER_REFERENCE_TAKEN` (field `orderReference`) with **`metadata.error.details.orderId`** naming the existing order; nothing is written. This is what makes a deliberate resend safe.\n\n**Idempotency-Key lifecycle (Postman).** The pre-request script mints `cloudIdempotencyKey` only when none is held (shared with the Cloud master writes). After an **uncertain** outcome — any `504`, or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED` — the key is **kept**, so an accidental resend carries the same key and the cloud refuses it (`409`) instead of running it again; a resend with a changed body under the kept key (for example a new reference) is refused `409 IDEMPOTENCY_KEY_REUSED`. After any definite answer (200, 4xx refusal, 502, 503) it is cleared. The cloud never stores results, so the same key never replays the first answer.\n\n**Uncertain write handling.**\n- `504 WRITE_RESULT_UNKNOWN` (the PC's answer did not reach AI Zeny; `details.reconciliation` `notChecked`) and `504 BUSY_WRITE_UNCERTAIN` (BUSY stopped while saving; `details.reconciliation` `found` + `orderId`, `notFound` or `notChecked`) are **not** successes and **not** failures. Never retry blind and **never with a new reference**.\n- First look the order up (Cloud Relay → Registers, Orders & Invoices → Pending sales orders, or BUSY) by `orderReference`.\n- To recover deliberately: unset `cloudIdempotencyKey`, keep `salesOrderReference` unchanged, set `confirmMutating` = `yes`, send once. If the first send saved, the answer is `409 SALES_ORDER_REFERENCE_TAKEN` with `details.orderId` and nothing new is written; otherwise the order is created once.\n- `502 BUSY_WRITE_UNVERIFIED`: BUSY **did** save, but its read-back differs (`details.orderId`, `details.mismatchedFields`). Check it in BUSY; do not resend.\n- `503 BUSY_COM_QUEUE_TIMEOUT`: refused before the job started, nothing written — the only retryable write error.\n- The cloud publishes a write once and never retries it; a write lives 400 s and the caller waits up to 405 s: give the request a long timeout.\n\n**Other errors:** 400 `BAD_REQUEST`, `INVALID_PARAMETER` (`field`); 401/403 token or scope; 404 `COMPANY_NOT_CONFIGURED`; 409 `SALES_ORDER_MASTER_CHANGED`, `MASTER_WRITE_PROVIDER_UNSUPPORTED`, `BUSY_COM_SIGN_IN_UNSUPPORTED`, `COMPANY_DISABLED`, `FINANCIAL_YEAR_NOT_ALLOWED`; 413 `REQUEST_TOO_LARGE`; 422 `MASTER_REFERENCE_NOT_FOUND`, `MASTER_REFERENCE_AMBIGUOUS`, `SALES_ORDER_SALE_TYPE_UNSUPPORTED`, `SALES_ORDER_TAX_UNSUPPORTED`, `BUSY_DATA_INCONSISTENT`; 502 `BUSY_WRITE_FAILED`, `DEVICE_ERROR`; 503 `BUSY_COM_*`; 504 `BUSY_COM_TIMEOUT`.\n\n**Safe test guidance:** only the development-test company (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`) with a **new, unique** `salesOrderReference` (current value) for each new order — the request is skipped without one. A created test order stays in BUSY. Saved examples are synthetic. Contract: `docs/public-api/AI-Zeny-Cloud-API-V1.md` (Sales-order create) and the operation reference.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- Lines also take `description` and Manual `amounts`. Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_ORDER_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n- Write admission (PC from Windows `53b556f`): `409 BUSY_WRITE_REFERENCE_IN_PROGRESS` (field `orderReference`; another write owns this reference — wait for its result, never resend it under another key), `409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED` (an earlier write with this reference needs review and may have saved — never repost it; look it up by `orderReference`), `503 BUSY_WRITE_ADMISSION_UNAVAILABLE` (nothing started). None is retryable; each is a definite answer, so the test clears `cloudIdempotencyKey`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000007","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNVERIFIED\",\n      \"message\": \"BUSY saved the sales order, but its read-back differs from what was sent. Check the order in BUSY; do not send it again.\",\n      \"details\": { \"orderId\": 8803, \"mismatchedFields\": [\"lines[0].netRate\", \"totals.amount\"] }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000007\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"1a556569-e9d9-62a7-fbfc-a40955a54497"},{"name":"⚠ BUSY sales invoice – create (writes to BUSY)","id":"8f3859b7-18b3-9fb5-83e6-e31a5041788a","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{cloudIdempotencyKey}}","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 2, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Postman cloud test line\"] },\n    { \"item\": { \"name\": \"Parle G\" }, \"quantity\": 2.5, \"rate\": 20.10 }\n  ],\n  \"narration\": \"Postman cloud test invoice\",\n  \"transport\": \"Synthetic Transport Co\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-invoice-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/sales-invoice-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)\n<strong>Status (2026-10-23):</strong> deployed and live (release <code>790395a</code>). Windows relays sales invoices from release 0.0.12 onward; an earlier PC version answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>invoiceReference</code>, <code>date</code>, <code>customer</code>, <code>saleType</code>, <code>materialCenter</code>, <code>lines</code>, <code>lines[].item</code>, <code>lines[].quantity</code>, <code>lines[].rate</code> · <strong>Optional:</strong> <code>voucherSeries</code>, <code>dueDate</code>, <code>lines[].discountPercent</code>, <code>lines[].mrp</code>, <code>lines[].description</code>, <code>billing</code>, <code>narration</code>, <code>transport</code>, <code>grNumber</code>, <code>vehicleNumber</code>, <code>station</code> · operation <code>busy.sales-invoices.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.</strong> Same operation, body and answer as the Local request <em>Local PC → ⚠ Voucher Create → ⚠ BUSY sales invoice – create</em>, called through the Cloud Relay with the organization's cloud token (the same token that reads). <strong>Create only</strong>: it never changes, cancels or deletes an invoice, never converts an order, and makes no e-invoice. <strong>SQL Server companies with a SQL login, and Access companies</strong> (the PC decides: Windows <code>6c5776d</code> or later accepts Access; an earlier PC answers Access with <code>409 MASTER_WRITE_PROVIDER_UNSUPPORTED</code>). Never run it from scripts or a collection run.</p>\n<p><strong>Body</strong> (at most 128 KiB, else <code>413 REQUEST_TOO_LARGE</code>; the PC also accepts at most 64 KiB per signed command, so a body whose lines carry long names and four long descriptions each may be refused <code>413</code> before anything is recorded or sent):</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Required</th>\n<th>Rule</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>companyCode</code>, <code>financialYear</code></td>\n<td>yes</td>\n<td>one company and one four-digit starting year within the token's scope</td>\n</tr>\n<tr>\n<td><code>invoiceReference</code></td>\n<td>yes</td>\n<td>your own reference, 1-60 characters (trimmed); unique among the company's sales invoices of the year</td>\n</tr>\n<tr>\n<td><code>date</code></td>\n<td>yes</td>\n<td><code>YYYY-MM-DD</code>, inside the financial year</td>\n</tr>\n<tr>\n<td><code>dueDate</code></td>\n<td>optional</td>\n<td><code>YYYY-MM-DD</code>, on or after <code>date</code>, at most five years later; only for a customer kept bill by bill (the bill reference is then named by <code>invoiceReference</code>)</td>\n</tr>\n<tr>\n<td><code>customer</code>, <code>saleType</code>, <code>materialCenter</code></td>\n<td>yes</td>\n<td><code>{ \"code\": n }</code> or <code>{ \"name\": \"…\" }</code>, each resolving to exactly one existing master</td>\n</tr>\n<tr>\n<td><code>voucherSeries</code></td>\n<td>optional</td>\n<td>same form; needed when the company has more than one sales-invoice series</td>\n</tr>\n<tr>\n<td><code>lines</code></td>\n<td>yes</td>\n<td>1-100: <code>item</code>, <code>quantity</code> (&gt; 0, ≤ 3 decimals), <code>rate</code> (≥ 0, tax-exclusive, ≤ 2 decimals), optional <code>discountPercent</code> (0-100, ≤ 2 decimals; the rate less the discount must come to ≤ 2 decimals), <code>mrp</code> (≥ 0, ≤ 2 decimals), <code>description</code> (1-10 positions of at most 40 characters; see below)</td>\n</tr>\n<tr>\n<td><code>billing</code></td>\n<td>optional</td>\n<td><code>{ name (1-60, required), address1-address4 (1-40), mobile, email }</code> — this invoice only</td>\n</tr>\n<tr>\n<td><code>narration</code></td>\n<td>optional</td>\n<td>1-94</td>\n</tr>\n<tr>\n<td><code>transport</code>, <code>grNumber</code>, <code>vehicleNumber</code>, <code>station</code></td>\n<td>optional</td>\n<td>1-30 each</td>\n</tr>\n<tr>\n<td>Manual GST <code>amounts</code>/<code>totals</code>, <code>salesman</code>, <code>eInvoiceRequired</code> and <code>queue</code> are accepted (see below); invoice numbers, XML and any other member are refused (<code>400 BAD_REQUEST</code>).</td>\n<td></td>\n<td></td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Duplicates and unknown outcomes.</strong> A second invoice with the same <code>invoiceReference</code> is refused <code>409 SALES_INVOICE_REFERENCE_TAKEN</code> with <code>details.invoiceId</code> of the existing invoice; nothing is written. After <code>504 WRITE_RESULT_UNKNOWN</code> or <code>504 BUSY_WRITE_UNCERTAIN</code> do not resend blind and never with a new reference: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Look the invoice up by <code>invoiceReference</code>; to recover deliberately, unset <code>cloudIdempotencyKey</code> and resend the <strong>same</strong> body: it answers <code>409 SALES_INVOICE_REFERENCE_TAKEN</code> with <code>details.invoiceId</code> if the first send saved. <code>502 BUSY_WRITE_UNVERIFIED</code> = saved but the read-back differs (<code>details.invoiceId</code>, <code>details.mismatchedFields</code>): check it in BUSY, do not resend.</p>\n<p><strong>Other refusals:</strong> <code>409 SALES_INVOICE_BILL_REFERENCE_TAKEN</code>, <code>409 SALES_INVOICE_MASTER_CHANGED</code>, <code>422 SALES_INVOICE_SALE_TYPE_UNSUPPORTED</code> / <code>_TAX_UNSUPPORTED</code> / <code>_ITEM_UNSUPPORTED</code> (serial-number, batch or parameter items) / <code>_DUE_DATE_UNSUPPORTED</code>, <code>422 MASTER_REFERENCE_NOT_FOUND</code> / <code>_AMBIGUOUS</code>, <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (not started; the only retryable code).</p>\n<p><strong>Safe test guidance:</strong> development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); set <code>salesInvoiceReference</code> to a new, unique test reference before each send; test invoices stay in BUSY (never delete or reuse them). The examples are synthetic.</p>\n<p><strong>Durable queue:</strong> optional strict <code>queue</code> (omitted or <code>false</code>: synchronous; <code>true</code>: a <code>202</code> job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.</p>\n<hr />\n<p><strong>Parity update (2026-10-23, deployed in release <code>790395a</code>; the PC must be Windows <code>6c5776d</code> or later for these members).</strong> This request's body sends only the basic members. New optional members and codes:</p>\n<ul>\n<li><code>queue</code> (optional, <code>true</code> or <code>false</code>, default <code>false</code>; <code>null</code> is refused <code>400</code>): with <code>true</code> the PC accepts the write on its durable queue and the answer is <strong><code>202</code></strong> with <code>data: null</code> and <code>metadata.queued: true</code>, <code>metadata.jobId</code> (32 hex), <code>metadata.status</code> — acceptance, <strong>not</strong> a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable <code>companyCode</code>/four-digit <code>financialYear</code>; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (<code>202</code>) and fails there. The cloud sends it once.</li>\n<li>GST modes: <code>taxCalculation</code> (<code>auto</code> default, or <code>manual</code>) and <code>pricingMode</code> (<code>gstExclusive</code> default, or <code>gstInclusive</code>, which must match the voucher type's inclusive flag). Manual needs every line's <code>amounts { taxableAmount, cgst, sgst, igst, amount }</code> and the voucher <code>totals</code> (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: <code>422 GST_AMOUNTS_INVALID</code>, <code>422 GST_MODE_UNSUPPORTED</code>, <code>409 GST_CONFIGURATION_CHANGED</code>.</li>\n<li><code>salesman</code> (optional): <code>{ \"code\": n }</code> or <code>{ \"name\": \"…\" }</code>; omitted or <code>null</code> keeps BUSY's default. Codes: <code>409 SALESMAN_CONFIGURATION_UNSUPPORTED</code>, <code>409 SALESMAN_CONFIGURATION_CHANGED</code>.</li>\n<li><code>eInvoiceRequired</code> (optional): <code>true</code>/<code>false</code> sets BUSY's E-Invoice Required flag; <code>null</code> or absent keeps BUSY's behaviour; no IRN or E-Way Bill is generated.</li>\n<li>Line <code>description</code>: 1-10 positions of at most 40 characters (<code>null</code> or empty keeps a position empty; at least one holds text); the series must allow that many lines (<code>422 DESCRIPTION_LINE_NOT_ALLOWED</code>). <code>422 SALES_INVOICE_SERIES_UNSUPPORTED</code>.</li>\n<li>Shared refusals of every write, answered before anything is written: <code>403 PLAN_FEATURE_NOT_INCLUDED</code>, <code>409 PLAN_NOT_KNOWN</code>, <code>503 BUSY_COM_RECOVERY_REQUIRED</code>, <code>409 BUSY_WRITE_TARGET_CHANGED</code>, <code>422 BUSY_SETTING_REQUIRED</code>, <code>502 BUSY_SETTINGS_UNREADABLE</code>; queue refusals <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>, <code>503 WRITE_QUEUE_UNAVAILABLE</code>.</li>\n<li>Write admission (PC from Windows <code>53b556f</code>): <code>409 BUSY_WRITE_REFERENCE_IN_PROGRESS</code> (field <code>invoiceReference</code>; another write owns this reference — wait for its result, never resend it under another key), <code>409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED</code> (an earlier write with this reference needs review and may have saved — never repost it; look it up by <code>invoiceReference</code>), <code>503 BUSY_WRITE_ADMISSION_UNAVAILABLE</code> (nothing started). None is retryable; each is a definite answer, so the test clears <code>cloudIdempotencyKey</code>.</li>\n</ul>\n<p>Scenario requests for the new members are in this folder, named <code>⚠ Scenario – …</code> and <code>⚠ EXPECTED REFUSAL …</code>; they are guarded like this one (<code>confirmMutating</code> = <code>yes</code>, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Cloud Relay has not deployed the new numbering schema; these are documentation examples only. Do not Send until Cloud parity is deployed and verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 2,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Postman cloud test line\"\n      ]\n    },\n    {\n      \"item\": {\n        \"name\": \"Parle G\"\n      },\n      \"quantity\": 2.5,\n      \"rate\": 20.1\n    }\n  ],\n  \"narration\": \"Postman cloud test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 2,\n      \"rate\": 150,\n      \"discountPercent\": 10,\n      \"description\": [\n        \"Postman cloud test line\"\n      ]\n    },\n    {\n      \"item\": {\n        \"name\": \"Parle G\"\n      },\n      \"quantity\": 2.5,\n      \"rate\": 20.1\n    }\n  ],\n  \"narration\": \"Postman cloud test invoice\",\n  \"transport\": \"Synthetic Transport Co\",\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","urlObject":{"path":["v1","sales-invoice-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"fe3e808b-847e-da1e-1f91-72048d3808d2","name":"200 – invoice created (local GST, billing from the customer) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 2, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Postman cloud test line\"] },\n    { \"item\": { \"name\": \"Parle G\" }, \"quantity\": 2.5, \"rate\": 20.10 }\n  ],\n  \"narration\": \"Postman cloud test invoice\",\n  \"transport\": \"Synthetic Transport Co\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-invoice-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-invoice-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). Windows relays sales invoices from release 0.0.12 onward; an earlier PC version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `invoiceReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · **Optional:** `voucherSeries`, `dueDate`, `lines[].discountPercent`, `lines[].mrp`, `lines[].description`, `billing`, `narration`, `transport`, `grNumber`, `vehicleNumber`, `station` · operation `busy.sales-invoices.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales invoice – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads). **Create only**: it never changes, cancels or deletes an invoice, never converts an order, and makes no e-invoice. **SQL Server companies with a SQL login, and Access companies** (the PC decides: Windows `6c5776d` or later accepts Access; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 128 KiB, else `413 REQUEST_TOO_LARGE`; the PC also accepts at most 64 KiB per signed command, so a body whose lines carry long names and four long descriptions each may be refused `413` before anything is recorded or sent):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `invoiceReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's sales invoices of the year |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `dueDate` | optional | `YYYY-MM-DD`, on or after `date`, at most five years later; only for a customer kept bill by bill (the bill reference is then named by `invoiceReference`) |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`, each resolving to exactly one existing master |\n| `voucherSeries` | optional | same form; needed when the company has more than one sales-invoice series |\n| `lines` | yes | 1-100: `item`, `quantity` (> 0, ≤ 3 decimals), `rate` (≥ 0, tax-exclusive, ≤ 2 decimals), optional `discountPercent` (0-100, ≤ 2 decimals; the rate less the discount must come to ≤ 2 decimals), `mrp` (≥ 0, ≤ 2 decimals), `description` (1-10 positions of at most 40 characters; see below) |\n| `billing` | optional | `{ name (1-60, required), address1-address4 (1-40), mobile, email }` — this invoice only |\n| `narration` | optional | 1-94 |\n| `transport`, `grNumber`, `vehicleNumber`, `station` | optional | 1-30 each |\nManual GST `amounts`/`totals`, `salesman`, `eInvoiceRequired` and `queue` are accepted (see below); invoice numbers, XML and any other member are refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second invoice with the same `invoiceReference` is refused `409 SALES_INVOICE_REFERENCE_TAKEN` with `details.invoiceId` of the existing invoice; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the invoice up by `invoiceReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body: it answers `409 SALES_INVOICE_REFERENCE_TAKEN` with `details.invoiceId` if the first send saved. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back differs (`details.invoiceId`, `details.mismatchedFields`): check it in BUSY, do not resend.\n\n**Other refusals:** `409 SALES_INVOICE_BILL_REFERENCE_TAKEN`, `409 SALES_INVOICE_MASTER_CHANGED`, `422 SALES_INVOICE_SALE_TYPE_UNSUPPORTED` / `_TAX_UNSUPPORTED` / `_ITEM_UNSUPPORTED` (serial-number, batch or parameter items) / `_DUE_DATE_UNSUPPORTED`, `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `503 BUSY_COM_QUEUE_TIMEOUT` (not started; the only retryable code).\n\n**Safe test guidance:** development-test company only (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`); set `salesInvoiceReference` to a new, unique test reference before each send; test invoices stay in BUSY (never delete or reuse them). The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- `eInvoiceRequired` (optional): `true`/`false` sets BUSY's E-Invoice Required flag; `null` or absent keeps BUSY's behaviour; no IRN or E-Way Bill is generated.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_INVOICE_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n- Write admission (PC from Windows `53b556f`): `409 BUSY_WRITE_REFERENCE_IN_PROGRESS` (field `invoiceReference`; another write owns this reference — wait for its result, never resend it under another key), `409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED` (an earlier write with this reference needs review and may have saved — never repost it; look it up by `invoiceReference`), `503 BUSY_WRITE_ADMISSION_UNAVAILABLE` (nothing started). None is retryable; each is a definite answer, so the test clears `cloudIdempotencyKey`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000101","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"invoiceId\": 9101,\n    \"invoiceNumber\": \"INV-31\",\n    \"invoiceReference\": \"INV-SYNTH-0001\",\n    \"date\": \"2026-10-16\",\n    \"voucherSeries\": { \"code\": 262, \"name\": \"Main\" },\n    \"customer\": { \"code\": 7001, \"name\": \"Synthetic Traders\" },\n    \"saleType\": { \"code\": 1223, \"name\": \"Local-ItemWise\" },\n    \"taxation\": \"local\",\n    \"materialCenter\": { \"code\": 201, \"name\": \"Main Store\" },\n    \"lines\": [\n      { \"lineNumber\": 1, \"item\": { \"code\": 9401, \"name\": \"Synthetic Item\" }, \"unit\": \"Pcs.\", \"quantity\": 2, \"rate\": 150, \"discountPercent\": 10, \"netRate\": 135, \"taxableAmount\": 270, \"cgst\": 16.2, \"sgst\": 16.2, \"igst\": 0, \"taxAmount\": 32.4, \"amount\": 302.4, \"mrp\": 180, \"description\": [\"Synthetic test line\"] }\n    ],\n    \"totals\": { \"quantity\": 2, \"taxableAmount\": 270, \"cgst\": 16.2, \"sgst\": 16.2, \"igst\": 0, \"taxAmount\": 32.4, \"amount\": 302.4 },\n    \"ledger\": [\n      { \"account\": { \"code\": 7001, \"name\": \"Synthetic Traders\" }, \"debit\": 302.4, \"credit\": 0 },\n      { \"account\": { \"code\": 501, \"name\": \"Sales\" }, \"debit\": 0, \"credit\": 270 },\n      { \"account\": { \"code\": 611, \"name\": \"CGST Output\" }, \"debit\": 0, \"credit\": 16.2 },\n      { \"account\": { \"code\": 612, \"name\": \"SGST Output\" }, \"debit\": 0, \"credit\": 16.2 }\n    ],\n    \"billReference\": { \"number\": \"INV-31\", \"dueDate\": \"2026-11-15\", \"amount\": 302.4, \"dueDateSource\": \"customerCreditDays\" },\n    \"billing\": { \"source\": \"customer\", \"name\": \"Synthetic Traders\", \"address1\": \"1 Example Road\", \"address2\": null, \"address3\": null, \"address4\": null, \"mobile\": \"9800000000\", \"email\": null, \"gstNumber\": null, \"panNumber\": null, \"state\": \"Synthetic State\" },\n    \"otherDetails\": { \"narration\": \"Synthetic invoice\", \"transport\": \"Synthetic Transport Co\", \"grNumber\": null, \"vehicleNumber\": null, \"station\": null }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-invoices.create\",\n    \"requestId\": \"rq_0SYNTHET1C0000000000000101\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 1,\n    \"verification\": [\"busyReadBack\", \"savedRows\"],\n    \"elapsedMs\": 8120,\n    \"executedAt\": \"2026-10-16T10:00:00.0000000+05:30\"\n  }\n}"},{"id":"9b65aefa-1b9d-cb59-7658-38ec1ec5b79d","name":"409 – duplicate invoiceReference (details.invoiceId; nothing written) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 2, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Postman cloud test line\"] },\n    { \"item\": { \"name\": \"Parle G\" }, \"quantity\": 2.5, \"rate\": 20.10 }\n  ],\n  \"narration\": \"Postman cloud test invoice\",\n  \"transport\": \"Synthetic Transport Co\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-invoice-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-invoice-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). Windows relays sales invoices from release 0.0.12 onward; an earlier PC version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `invoiceReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · **Optional:** `voucherSeries`, `dueDate`, `lines[].discountPercent`, `lines[].mrp`, `lines[].description`, `billing`, `narration`, `transport`, `grNumber`, `vehicleNumber`, `station` · operation `busy.sales-invoices.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales invoice – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads). **Create only**: it never changes, cancels or deletes an invoice, never converts an order, and makes no e-invoice. **SQL Server companies with a SQL login, and Access companies** (the PC decides: Windows `6c5776d` or later accepts Access; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 128 KiB, else `413 REQUEST_TOO_LARGE`; the PC also accepts at most 64 KiB per signed command, so a body whose lines carry long names and four long descriptions each may be refused `413` before anything is recorded or sent):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `invoiceReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's sales invoices of the year |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `dueDate` | optional | `YYYY-MM-DD`, on or after `date`, at most five years later; only for a customer kept bill by bill (the bill reference is then named by `invoiceReference`) |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`, each resolving to exactly one existing master |\n| `voucherSeries` | optional | same form; needed when the company has more than one sales-invoice series |\n| `lines` | yes | 1-100: `item`, `quantity` (> 0, ≤ 3 decimals), `rate` (≥ 0, tax-exclusive, ≤ 2 decimals), optional `discountPercent` (0-100, ≤ 2 decimals; the rate less the discount must come to ≤ 2 decimals), `mrp` (≥ 0, ≤ 2 decimals), `description` (1-10 positions of at most 40 characters; see below) |\n| `billing` | optional | `{ name (1-60, required), address1-address4 (1-40), mobile, email }` — this invoice only |\n| `narration` | optional | 1-94 |\n| `transport`, `grNumber`, `vehicleNumber`, `station` | optional | 1-30 each |\nManual GST `amounts`/`totals`, `salesman`, `eInvoiceRequired` and `queue` are accepted (see below); invoice numbers, XML and any other member are refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second invoice with the same `invoiceReference` is refused `409 SALES_INVOICE_REFERENCE_TAKEN` with `details.invoiceId` of the existing invoice; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the invoice up by `invoiceReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body: it answers `409 SALES_INVOICE_REFERENCE_TAKEN` with `details.invoiceId` if the first send saved. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back differs (`details.invoiceId`, `details.mismatchedFields`): check it in BUSY, do not resend.\n\n**Other refusals:** `409 SALES_INVOICE_BILL_REFERENCE_TAKEN`, `409 SALES_INVOICE_MASTER_CHANGED`, `422 SALES_INVOICE_SALE_TYPE_UNSUPPORTED` / `_TAX_UNSUPPORTED` / `_ITEM_UNSUPPORTED` (serial-number, batch or parameter items) / `_DUE_DATE_UNSUPPORTED`, `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `503 BUSY_COM_QUEUE_TIMEOUT` (not started; the only retryable code).\n\n**Safe test guidance:** development-test company only (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`); set `salesInvoiceReference` to a new, unique test reference before each send; test invoices stay in BUSY (never delete or reuse them). The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- `eInvoiceRequired` (optional): `true`/`false` sets BUSY's E-Invoice Required flag; `null` or absent keeps BUSY's behaviour; no IRN or E-Way Bill is generated.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_INVOICE_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n- Write admission (PC from Windows `53b556f`): `409 BUSY_WRITE_REFERENCE_IN_PROGRESS` (field `invoiceReference`; another write owns this reference — wait for its result, never resend it under another key), `409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED` (an earlier write with this reference needs review and may have saved — never repost it; look it up by `invoiceReference`), `503 BUSY_WRITE_ADMISSION_UNAVAILABLE` (nothing started). None is retryable; each is a definite answer, so the test clears `cloudIdempotencyKey`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000102"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SALES_INVOICE_REFERENCE_TAKEN\",\n      \"message\": \"A sales invoice of this company and financial year already holds this invoiceReference. A create never changes an existing invoice; if your earlier call saved it, metadata.error.details.invoiceId names it.\",\n      \"field\": \"invoiceReference\",\n      \"details\": { \"invoiceId\": 9101 }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000102\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"22396c9a-7dae-bea7-a830-31755b15972d","name":"400 – dueDate before date (refused by the cloud, nothing sent) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 2, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Postman cloud test line\"] },\n    { \"item\": { \"name\": \"Parle G\" }, \"quantity\": 2.5, \"rate\": 20.10 }\n  ],\n  \"narration\": \"Postman cloud test invoice\",\n  \"transport\": \"Synthetic Transport Co\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-invoice-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-invoice-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). Windows relays sales invoices from release 0.0.12 onward; an earlier PC version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `invoiceReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · **Optional:** `voucherSeries`, `dueDate`, `lines[].discountPercent`, `lines[].mrp`, `lines[].description`, `billing`, `narration`, `transport`, `grNumber`, `vehicleNumber`, `station` · operation `busy.sales-invoices.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales invoice – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads). **Create only**: it never changes, cancels or deletes an invoice, never converts an order, and makes no e-invoice. **SQL Server companies with a SQL login, and Access companies** (the PC decides: Windows `6c5776d` or later accepts Access; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 128 KiB, else `413 REQUEST_TOO_LARGE`; the PC also accepts at most 64 KiB per signed command, so a body whose lines carry long names and four long descriptions each may be refused `413` before anything is recorded or sent):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `invoiceReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's sales invoices of the year |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `dueDate` | optional | `YYYY-MM-DD`, on or after `date`, at most five years later; only for a customer kept bill by bill (the bill reference is then named by `invoiceReference`) |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`, each resolving to exactly one existing master |\n| `voucherSeries` | optional | same form; needed when the company has more than one sales-invoice series |\n| `lines` | yes | 1-100: `item`, `quantity` (> 0, ≤ 3 decimals), `rate` (≥ 0, tax-exclusive, ≤ 2 decimals), optional `discountPercent` (0-100, ≤ 2 decimals; the rate less the discount must come to ≤ 2 decimals), `mrp` (≥ 0, ≤ 2 decimals), `description` (1-10 positions of at most 40 characters; see below) |\n| `billing` | optional | `{ name (1-60, required), address1-address4 (1-40), mobile, email }` — this invoice only |\n| `narration` | optional | 1-94 |\n| `transport`, `grNumber`, `vehicleNumber`, `station` | optional | 1-30 each |\nManual GST `amounts`/`totals`, `salesman`, `eInvoiceRequired` and `queue` are accepted (see below); invoice numbers, XML and any other member are refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second invoice with the same `invoiceReference` is refused `409 SALES_INVOICE_REFERENCE_TAKEN` with `details.invoiceId` of the existing invoice; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the invoice up by `invoiceReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body: it answers `409 SALES_INVOICE_REFERENCE_TAKEN` with `details.invoiceId` if the first send saved. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back differs (`details.invoiceId`, `details.mismatchedFields`): check it in BUSY, do not resend.\n\n**Other refusals:** `409 SALES_INVOICE_BILL_REFERENCE_TAKEN`, `409 SALES_INVOICE_MASTER_CHANGED`, `422 SALES_INVOICE_SALE_TYPE_UNSUPPORTED` / `_TAX_UNSUPPORTED` / `_ITEM_UNSUPPORTED` (serial-number, batch or parameter items) / `_DUE_DATE_UNSUPPORTED`, `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `503 BUSY_COM_QUEUE_TIMEOUT` (not started; the only retryable code).\n\n**Safe test guidance:** development-test company only (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`); set `salesInvoiceReference` to a new, unique test reference before each send; test invoices stay in BUSY (never delete or reuse them). The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- `eInvoiceRequired` (optional): `true`/`false` sets BUSY's E-Invoice Required flag; `null` or absent keeps BUSY's behaviour; no IRN or E-Way Bill is generated.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_INVOICE_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n- Write admission (PC from Windows `53b556f`): `409 BUSY_WRITE_REFERENCE_IN_PROGRESS` (field `invoiceReference`; another write owns this reference — wait for its result, never resend it under another key), `409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED` (an earlier write with this reference needs review and may have saved — never repost it; look it up by `invoiceReference`), `503 BUSY_WRITE_ADMISSION_UNAVAILABLE` (nothing started). None is retryable; each is a definite answer, so the test clears `cloudIdempotencyKey`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"dueDate must be a date as YYYY-MM-DD, on or after date and at most five years after it.\",\n      \"field\": \"dueDate\"\n    },\n    \"requestId\": \"req_0SYNTHET1C0000000000000103\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"807a02c2-957b-a697-a21f-1a45dadf2720","name":"422 – tracked item refused by the PC (nothing written) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 2, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Postman cloud test line\"] },\n    { \"item\": { \"name\": \"Parle G\" }, \"quantity\": 2.5, \"rate\": 20.10 }\n  ],\n  \"narration\": \"Postman cloud test invoice\",\n  \"transport\": \"Synthetic Transport Co\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-invoice-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-invoice-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). Windows relays sales invoices from release 0.0.12 onward; an earlier PC version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `invoiceReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · **Optional:** `voucherSeries`, `dueDate`, `lines[].discountPercent`, `lines[].mrp`, `lines[].description`, `billing`, `narration`, `transport`, `grNumber`, `vehicleNumber`, `station` · operation `busy.sales-invoices.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales invoice – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads). **Create only**: it never changes, cancels or deletes an invoice, never converts an order, and makes no e-invoice. **SQL Server companies with a SQL login, and Access companies** (the PC decides: Windows `6c5776d` or later accepts Access; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 128 KiB, else `413 REQUEST_TOO_LARGE`; the PC also accepts at most 64 KiB per signed command, so a body whose lines carry long names and four long descriptions each may be refused `413` before anything is recorded or sent):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `invoiceReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's sales invoices of the year |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `dueDate` | optional | `YYYY-MM-DD`, on or after `date`, at most five years later; only for a customer kept bill by bill (the bill reference is then named by `invoiceReference`) |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`, each resolving to exactly one existing master |\n| `voucherSeries` | optional | same form; needed when the company has more than one sales-invoice series |\n| `lines` | yes | 1-100: `item`, `quantity` (> 0, ≤ 3 decimals), `rate` (≥ 0, tax-exclusive, ≤ 2 decimals), optional `discountPercent` (0-100, ≤ 2 decimals; the rate less the discount must come to ≤ 2 decimals), `mrp` (≥ 0, ≤ 2 decimals), `description` (1-10 positions of at most 40 characters; see below) |\n| `billing` | optional | `{ name (1-60, required), address1-address4 (1-40), mobile, email }` — this invoice only |\n| `narration` | optional | 1-94 |\n| `transport`, `grNumber`, `vehicleNumber`, `station` | optional | 1-30 each |\nManual GST `amounts`/`totals`, `salesman`, `eInvoiceRequired` and `queue` are accepted (see below); invoice numbers, XML and any other member are refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second invoice with the same `invoiceReference` is refused `409 SALES_INVOICE_REFERENCE_TAKEN` with `details.invoiceId` of the existing invoice; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the invoice up by `invoiceReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body: it answers `409 SALES_INVOICE_REFERENCE_TAKEN` with `details.invoiceId` if the first send saved. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back differs (`details.invoiceId`, `details.mismatchedFields`): check it in BUSY, do not resend.\n\n**Other refusals:** `409 SALES_INVOICE_BILL_REFERENCE_TAKEN`, `409 SALES_INVOICE_MASTER_CHANGED`, `422 SALES_INVOICE_SALE_TYPE_UNSUPPORTED` / `_TAX_UNSUPPORTED` / `_ITEM_UNSUPPORTED` (serial-number, batch or parameter items) / `_DUE_DATE_UNSUPPORTED`, `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `503 BUSY_COM_QUEUE_TIMEOUT` (not started; the only retryable code).\n\n**Safe test guidance:** development-test company only (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`); set `salesInvoiceReference` to a new, unique test reference before each send; test invoices stay in BUSY (never delete or reuse them). The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- `eInvoiceRequired` (optional): `true`/`false` sets BUSY's E-Invoice Required flag; `null` or absent keeps BUSY's behaviour; no IRN or E-Way Bill is generated.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_INVOICE_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n- Write admission (PC from Windows `53b556f`): `409 BUSY_WRITE_REFERENCE_IN_PROGRESS` (field `invoiceReference`; another write owns this reference — wait for its result, never resend it under another key), `409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED` (an earlier write with this reference needs review and may have saved — never repost it; look it up by `invoiceReference`), `503 BUSY_WRITE_ADMISSION_UNAVAILABLE` (nothing started). None is retryable; each is a definite answer, so the test clears `cloudIdempotencyKey`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000104"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SALES_INVOICE_ITEM_UNSUPPORTED\",\n      \"message\": \"BUSY keeps this item batch-wise; AI Zeny does not create invoices that need serial-number, batch or parameter details. Enter this invoice in BUSY.\",\n      \"field\": \"lines[0].item\"\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000104\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"90f23949-2c18-6611-ae12-9fd6b7b14c3f","name":"502 – BUSY_WRITE_UNVERIFIED (saved, read-back differs; do not resend) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 2, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Postman cloud test line\"] },\n    { \"item\": { \"name\": \"Parle G\" }, \"quantity\": 2.5, \"rate\": 20.10 }\n  ],\n  \"narration\": \"Postman cloud test invoice\",\n  \"transport\": \"Synthetic Transport Co\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-invoice-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-invoice-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). Windows relays sales invoices from release 0.0.12 onward; an earlier PC version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `invoiceReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · **Optional:** `voucherSeries`, `dueDate`, `lines[].discountPercent`, `lines[].mrp`, `lines[].description`, `billing`, `narration`, `transport`, `grNumber`, `vehicleNumber`, `station` · operation `busy.sales-invoices.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales invoice – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads). **Create only**: it never changes, cancels or deletes an invoice, never converts an order, and makes no e-invoice. **SQL Server companies with a SQL login, and Access companies** (the PC decides: Windows `6c5776d` or later accepts Access; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 128 KiB, else `413 REQUEST_TOO_LARGE`; the PC also accepts at most 64 KiB per signed command, so a body whose lines carry long names and four long descriptions each may be refused `413` before anything is recorded or sent):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `invoiceReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's sales invoices of the year |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `dueDate` | optional | `YYYY-MM-DD`, on or after `date`, at most five years later; only for a customer kept bill by bill (the bill reference is then named by `invoiceReference`) |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`, each resolving to exactly one existing master |\n| `voucherSeries` | optional | same form; needed when the company has more than one sales-invoice series |\n| `lines` | yes | 1-100: `item`, `quantity` (> 0, ≤ 3 decimals), `rate` (≥ 0, tax-exclusive, ≤ 2 decimals), optional `discountPercent` (0-100, ≤ 2 decimals; the rate less the discount must come to ≤ 2 decimals), `mrp` (≥ 0, ≤ 2 decimals), `description` (1-10 positions of at most 40 characters; see below) |\n| `billing` | optional | `{ name (1-60, required), address1-address4 (1-40), mobile, email }` — this invoice only |\n| `narration` | optional | 1-94 |\n| `transport`, `grNumber`, `vehicleNumber`, `station` | optional | 1-30 each |\nManual GST `amounts`/`totals`, `salesman`, `eInvoiceRequired` and `queue` are accepted (see below); invoice numbers, XML and any other member are refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second invoice with the same `invoiceReference` is refused `409 SALES_INVOICE_REFERENCE_TAKEN` with `details.invoiceId` of the existing invoice; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the invoice up by `invoiceReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body: it answers `409 SALES_INVOICE_REFERENCE_TAKEN` with `details.invoiceId` if the first send saved. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back differs (`details.invoiceId`, `details.mismatchedFields`): check it in BUSY, do not resend.\n\n**Other refusals:** `409 SALES_INVOICE_BILL_REFERENCE_TAKEN`, `409 SALES_INVOICE_MASTER_CHANGED`, `422 SALES_INVOICE_SALE_TYPE_UNSUPPORTED` / `_TAX_UNSUPPORTED` / `_ITEM_UNSUPPORTED` (serial-number, batch or parameter items) / `_DUE_DATE_UNSUPPORTED`, `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `503 BUSY_COM_QUEUE_TIMEOUT` (not started; the only retryable code).\n\n**Safe test guidance:** development-test company only (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`); set `salesInvoiceReference` to a new, unique test reference before each send; test invoices stay in BUSY (never delete or reuse them). The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- `eInvoiceRequired` (optional): `true`/`false` sets BUSY's E-Invoice Required flag; `null` or absent keeps BUSY's behaviour; no IRN or E-Way Bill is generated.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_INVOICE_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n- Write admission (PC from Windows `53b556f`): `409 BUSY_WRITE_REFERENCE_IN_PROGRESS` (field `invoiceReference`; another write owns this reference — wait for its result, never resend it under another key), `409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED` (an earlier write with this reference needs review and may have saved — never repost it; look it up by `invoiceReference`), `503 BUSY_WRITE_ADMISSION_UNAVAILABLE` (nothing started). None is retryable; each is a definite answer, so the test clears `cloudIdempotencyKey`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000105"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNVERIFIED\",\n      \"message\": \"BUSY saved the sales invoice, but its read-back differs from the request in the fields listed in metadata.error.details.mismatchedFields. The invoice is in BUSY; check it there and do not send it again.\",\n      \"details\": { \"invoiceId\": 9102, \"mismatchedFields\": [\"lines[0].amount\", \"saved.billReference\"] }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000105\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"372591f3-bc95-f840-55dd-6a346347bfb1","name":"504 – WRITE_RESULT_UNKNOWN (PC's answer lost): key kept, do not resend blind [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 2, \"rate\": 150, \"discountPercent\": 10, \"description\": [\"Postman cloud test line\"] },\n    { \"item\": { \"name\": \"Parle G\" }, \"quantity\": 2.5, \"rate\": 20.10 }\n  ],\n  \"narration\": \"Postman cloud test invoice\",\n  \"transport\": \"Synthetic Transport Co\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-invoice-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-invoice-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). Windows relays sales invoices from release 0.0.12 onward; an earlier PC version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `invoiceReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines`, `lines[].item`, `lines[].quantity`, `lines[].rate` · **Optional:** `voucherSeries`, `dueDate`, `lines[].discountPercent`, `lines[].mrp`, `lines[].description`, `billing`, `narration`, `transport`, `grNumber`, `vehicleNumber`, `station` · operation `busy.sales-invoices.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales invoice – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads). **Create only**: it never changes, cancels or deletes an invoice, never converts an order, and makes no e-invoice. **SQL Server companies with a SQL login, and Access companies** (the PC decides: Windows `6c5776d` or later accepts Access; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 128 KiB, else `413 REQUEST_TOO_LARGE`; the PC also accepts at most 64 KiB per signed command, so a body whose lines carry long names and four long descriptions each may be refused `413` before anything is recorded or sent):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `invoiceReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's sales invoices of the year |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `dueDate` | optional | `YYYY-MM-DD`, on or after `date`, at most five years later; only for a customer kept bill by bill (the bill reference is then named by `invoiceReference`) |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`, each resolving to exactly one existing master |\n| `voucherSeries` | optional | same form; needed when the company has more than one sales-invoice series |\n| `lines` | yes | 1-100: `item`, `quantity` (> 0, ≤ 3 decimals), `rate` (≥ 0, tax-exclusive, ≤ 2 decimals), optional `discountPercent` (0-100, ≤ 2 decimals; the rate less the discount must come to ≤ 2 decimals), `mrp` (≥ 0, ≤ 2 decimals), `description` (1-10 positions of at most 40 characters; see below) |\n| `billing` | optional | `{ name (1-60, required), address1-address4 (1-40), mobile, email }` — this invoice only |\n| `narration` | optional | 1-94 |\n| `transport`, `grNumber`, `vehicleNumber`, `station` | optional | 1-30 each |\nManual GST `amounts`/`totals`, `salesman`, `eInvoiceRequired` and `queue` are accepted (see below); invoice numbers, XML and any other member are refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second invoice with the same `invoiceReference` is refused `409 SALES_INVOICE_REFERENCE_TAKEN` with `details.invoiceId` of the existing invoice; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the invoice up by `invoiceReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body: it answers `409 SALES_INVOICE_REFERENCE_TAKEN` with `details.invoiceId` if the first send saved. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back differs (`details.invoiceId`, `details.mismatchedFields`): check it in BUSY, do not resend.\n\n**Other refusals:** `409 SALES_INVOICE_BILL_REFERENCE_TAKEN`, `409 SALES_INVOICE_MASTER_CHANGED`, `422 SALES_INVOICE_SALE_TYPE_UNSUPPORTED` / `_TAX_UNSUPPORTED` / `_ITEM_UNSUPPORTED` (serial-number, batch or parameter items) / `_DUE_DATE_UNSUPPORTED`, `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `503 BUSY_COM_QUEUE_TIMEOUT` (not started; the only retryable code).\n\n**Safe test guidance:** development-test company only (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`); set `salesInvoiceReference` to a new, unique test reference before each send; test invoices stay in BUSY (never delete or reuse them). The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- `eInvoiceRequired` (optional): `true`/`false` sets BUSY's E-Invoice Required flag; `null` or absent keeps BUSY's behaviour; no IRN or E-Way Bill is generated.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_INVOICE_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n- Write admission (PC from Windows `53b556f`): `409 BUSY_WRITE_REFERENCE_IN_PROGRESS` (field `invoiceReference`; another write owns this reference — wait for its result, never resend it under another key), `409 BUSY_WRITE_REFERENCE_REVIEW_REQUIRED` (an earlier write with this reference needs review and may have saved — never repost it; look it up by `invoiceReference`), `503 BUSY_WRITE_ADMISSION_UNAVAILABLE` (nothing started). None is retryable; each is a definite answer, so the test clears `cloudIdempotencyKey`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000106"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"WRITE_RESULT_UNKNOWN\",\n      \"message\": \"The PC's answer to this sales invoice did not reach AI Zeny, so whether BUSY saved it is not known. Look the invoice up by its invoiceReference before trying again; a retry with the same invoiceReference is refused if the first one saved (409 SALES_INVOICE_REFERENCE_TAKEN with details.invoiceId).\",\n      \"details\": { \"reconciliation\": \"notChecked\" }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000106\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"8f3859b7-18b3-9fb5-83e6-e31a5041788a"},{"name":"⚠ BUSY receipt – create (writes to BUSY)","id":"15b2992c-34e2-ecbf-beb2-93ffd2aaee70","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"receiptReference\": \"{{receiptReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"party\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"amount\": 100,\n  \"instrumentNumber\": \"SYNTHETIC-001\",\n  \"shortNarration\": \"Postman cloud test receipt\",\n  \"narration\": \"Postman cloud test receipt (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/receipt-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/receipt-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)\n<strong>Status (2026-10-23):</strong> deployed and live (release <code>790395a</code>). The PC needs an AI Zeny version that relays receipts (Windows <code>0df569b</code> or later — <strong>not</strong> in public release 0.0.12; the development PC's installed candidate has it); an earlier version answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>receiptReference</code>, <code>date</code>, <code>account</code>, <code>party</code>, <code>amount</code> · <strong>Optional:</strong> <code>voucherSeries</code>, <code>allocations</code>, <code>instrumentNumber</code>, <code>shortNarration</code>, <code>narration</code> · operation <code>busy.receipts.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.</strong> Same operation, body and answer as the Local request <em>Local PC → ⚠ Voucher Create → ⚠ BUSY receipt – create</em>, called through the Cloud Relay with the organization's cloud token (the same token that reads): <strong>one</strong> cash-in-hand, bank or bank OD <code>account</code> receives <code>amount</code> from <strong>one</strong> <code>party</code>. <strong>Create only</strong>. <strong>SQL Server companies with a SQL login, and Access companies</strong> (Windows <code>6c5776d</code> or later; an earlier PC answers Access with <code>409 MASTER_WRITE_PROVIDER_UNSUPPORTED</code>). Never run it from scripts or a collection run.</p>\n<p><strong>Body</strong> (at most 64 KiB, else <code>413 REQUEST_TOO_LARGE</code>):</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Required</th>\n<th>Rule</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>companyCode</code>, <code>financialYear</code></td>\n<td>yes</td>\n<td>one company and one four-digit starting year within the token's scope</td>\n</tr>\n<tr>\n<td><code>receiptReference</code></td>\n<td>yes</td>\n<td>your own reference, 1-60 characters (trimmed); unique among the company's receipts of the year</td>\n</tr>\n<tr>\n<td><code>date</code></td>\n<td>yes</td>\n<td><code>YYYY-MM-DD</code>, inside the financial year</td>\n</tr>\n<tr>\n<td><code>account</code>, <code>party</code></td>\n<td>yes</td>\n<td><code>{ \"code\": n }</code> or <code>{ \"name\": \"…\" }</code>; the account must be cash in hand, bank or bank OD; the party neither</td>\n</tr>\n<tr>\n<td><code>voucherSeries</code></td>\n<td>optional</td>\n<td>needed when the company has more than one receipt series</td>\n</tr>\n<tr>\n<td><code>amount</code></td>\n<td>yes</td>\n<td>more than 0, at most 9999999999.99, at most 2 decimals</td>\n</tr>\n<tr>\n<td><code>allocations</code></td>\n<td>optional</td>\n<td>1-100, only for a party BUSY keeps bill by bill: <code>{ \"bill\": { \"number\": \"…\" }, \"amount\": n }</code> (one of the party's own outstanding bills, never over-settled) or <code>{ \"newReference\": { \"number\": \"…\", \"dueDate\": \"YYYY-MM-DD\" }, \"amount\": n }</code> (a number new to the party; due date on or after <code>date</code>, at most five years later, default <code>date</code>); each number once; together at most <code>amount</code> — the rest stays on account</td>\n</tr>\n<tr>\n<td><code>instrumentNumber</code>, <code>shortNarration</code>, <code>narration</code></td>\n<td>optional</td>\n<td>1-30, 1-40, 1-94</td>\n</tr>\n<tr>\n<td>No instrument type; any other member is refused (<code>400 BAD_REQUEST</code>).</td>\n<td></td>\n<td></td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Duplicates and unknown outcomes.</strong> A second receipt with the same <code>receiptReference</code> is refused <code>409 RECEIPT_REFERENCE_TAKEN</code> with <code>details.receiptId</code>; nothing is written. After <code>504 WRITE_RESULT_UNKNOWN</code> or <code>504 BUSY_WRITE_UNCERTAIN</code> do not resend blind and never with a new reference: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Look the receipt up by <code>receiptReference</code>; to recover deliberately, unset <code>cloudIdempotencyKey</code> and resend the <strong>same</strong> body. <code>502 BUSY_WRITE_UNVERIFIED</code> = saved but the read-back or a settled bill differs (<code>details.receiptId</code>, <code>details.mismatchedFields</code>): do not resend.</p>\n<p><strong>Other refusals:</strong> <code>409 RECEIPT_NEW_REFERENCE_TAKEN</code>, <code>409 RECEIPT_MASTER_CHANGED</code>, <code>422 RECEIPT_ACCOUNT_UNSUPPORTED</code>, <code>422 RECEIPT_ALLOCATION_UNSUPPORTED</code>, <code>422 RECEIPT_BILL_NOT_FOUND</code>, <code>422 RECEIPT_BILL_OVERSETTLED</code>, <code>422 MASTER_REFERENCE_NOT_FOUND</code> / <code>_AMBIGUOUS</code>, <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (the only retryable code).</p>\n<p><strong>Safe test guidance:</strong> development-test company only (<code>COMP0002</code> / <code>2026</code>); set <code>receiptReference</code> to a new, unique test reference before each send; to settle a bill, add an <code>allocations</code> entry with a bill number the party owes (for example a test invoice's <code>billReference.number</code>). Test receipts stay in BUSY. The examples are synthetic.</p>\n<p><strong>Durable queue:</strong> optional strict <code>queue</code> (omitted or <code>false</code>: synchronous; <code>true</code>: a <code>202</code> job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.</p>\n<hr />\n<p><strong>Parity update (2026-10-23, deployed in release <code>790395a</code>; the PC must be Windows <code>6c5776d</code> or later for these members).</strong> This request's body sends only the basic members. New optional members and codes:</p>\n<ul>\n<li><code>queue</code> (optional, <code>true</code> or <code>false</code>, default <code>false</code>; <code>null</code> is refused <code>400</code>): with <code>true</code> the PC accepts the write on its durable queue and the answer is <strong><code>202</code></strong> with <code>data: null</code> and <code>metadata.queued: true</code>, <code>metadata.jobId</code> (32 hex), <code>metadata.status</code> — acceptance, <strong>not</strong> a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable <code>companyCode</code>/four-digit <code>financialYear</code>; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (<code>202</code>) and fails there. The cloud sends it once.</li>\n<li>Shared refusals of every write, answered before anything is written: <code>403 PLAN_FEATURE_NOT_INCLUDED</code>, <code>409 PLAN_NOT_KNOWN</code>, <code>503 BUSY_COM_RECOVERY_REQUIRED</code>, <code>409 BUSY_WRITE_TARGET_CHANGED</code>, <code>422 BUSY_SETTING_REQUIRED</code>, <code>502 BUSY_SETTINGS_UNREADABLE</code>; queue refusals <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>, <code>503 WRITE_QUEUE_UNAVAILABLE</code>.</li>\n</ul>\n<p>Scenario requests for the new members are in this folder, named <code>⚠ Scenario – …</code> and <code>⚠ EXPECTED REFUSAL …</code>; they are guarded like this one (<code>confirmMutating</code> = <code>yes</code>, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Cloud Relay has not deployed the new numbering schema; these are documentation examples only. Do not Send until Cloud parity is deployed and verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"receiptReference\": \"{{receiptReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"account\": {\n    \"name\": \"Cash\"\n  },\n  \"party\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"amount\": 100,\n  \"instrumentNumber\": \"SYNTHETIC-001\",\n  \"shortNarration\": \"Postman cloud test receipt\",\n  \"narration\": \"Postman cloud test receipt (on account)\",\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"receiptReference\": \"{{receiptReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"account\": {\n    \"name\": \"Cash\"\n  },\n  \"party\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"amount\": 100,\n  \"instrumentNumber\": \"SYNTHETIC-001\",\n  \"shortNarration\": \"Postman cloud test receipt\",\n  \"narration\": \"Postman cloud test receipt (on account)\",\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","urlObject":{"path":["v1","receipt-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"87379fd5-04de-c3eb-bed2-08b1309f20bf","name":"200 – receipt created: a bill settled, an advance, the rest on account [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"receiptReference\": \"{{receiptReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"party\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"amount\": 100,\n  \"instrumentNumber\": \"SYNTHETIC-001\",\n  \"shortNarration\": \"Postman cloud test receipt\",\n  \"narration\": \"Postman cloud test receipt (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/receipt-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/receipt-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays receipts (Windows `0df569b` or later — **not** in public release 0.0.12; the development PC's installed candidate has it); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `receiptReference`, `date`, `account`, `party`, `amount` · **Optional:** `voucherSeries`, `allocations`, `instrumentNumber`, `shortNarration`, `narration` · operation `busy.receipts.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY receipt – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads): **one** cash-in-hand, bank or bank OD `account` receives `amount` from **one** `party`. **Create only**. **SQL Server companies with a SQL login, and Access companies** (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 64 KiB, else `413 REQUEST_TOO_LARGE`):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `receiptReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's receipts of the year |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `account`, `party` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`; the account must be cash in hand, bank or bank OD; the party neither |\n| `voucherSeries` | optional | needed when the company has more than one receipt series |\n| `amount` | yes | more than 0, at most 9999999999.99, at most 2 decimals |\n| `allocations` | optional | 1-100, only for a party BUSY keeps bill by bill: `{ \"bill\": { \"number\": \"…\" }, \"amount\": n }` (one of the party's own outstanding bills, never over-settled) or `{ \"newReference\": { \"number\": \"…\", \"dueDate\": \"YYYY-MM-DD\" }, \"amount\": n }` (a number new to the party; due date on or after `date`, at most five years later, default `date`); each number once; together at most `amount` — the rest stays on account |\n| `instrumentNumber`, `shortNarration`, `narration` | optional | 1-30, 1-40, 1-94 |\nNo instrument type; any other member is refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second receipt with the same `receiptReference` is refused `409 RECEIPT_REFERENCE_TAKEN` with `details.receiptId`; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the receipt up by `receiptReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back or a settled bill differs (`details.receiptId`, `details.mismatchedFields`): do not resend.\n\n**Other refusals:** `409 RECEIPT_NEW_REFERENCE_TAKEN`, `409 RECEIPT_MASTER_CHANGED`, `422 RECEIPT_ACCOUNT_UNSUPPORTED`, `422 RECEIPT_ALLOCATION_UNSUPPORTED`, `422 RECEIPT_BILL_NOT_FOUND`, `422 RECEIPT_BILL_OVERSETTLED`, `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `503 BUSY_COM_QUEUE_TIMEOUT` (the only retryable code).\n\n**Safe test guidance:** development-test company only (`COMP0002` / `2026`); set `receiptReference` to a new, unique test reference before each send; to settle a bill, add an `allocations` entry with a bill number the party owes (for example a test invoice's `billReference.number`). Test receipts stay in BUSY. The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000201","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"receiptId\": 9201,\n    \"receiptNumber\": \"RCPT-12\",\n    \"receiptReference\": \"RCPT-SYNTH-0001\",\n    \"date\": \"2026-10-16\",\n    \"voucherSeries\": { \"code\": 263, \"name\": \"Main\" },\n    \"account\": { \"code\": 301, \"name\": \"Cash\" },\n    \"party\": { \"code\": 7001, \"name\": \"Synthetic Traders\" },\n    \"amount\": 1500,\n    \"allocations\": [\n      { \"type\": \"bill\", \"number\": \"INV-31\", \"amount\": 302.4, \"dueDate\": \"2026-11-15\", \"outstandingBefore\": 302.4, \"outstandingAfter\": 0 },\n      { \"type\": \"newReference\", \"number\": \"ADV-SYNTH-1\", \"amount\": 500, \"dueDate\": \"2026-12-31\", \"outstandingBefore\": null, \"outstandingAfter\": null }\n    ],\n    \"allocatedAmount\": 802.4,\n    \"unallocatedAmount\": 697.6,\n    \"instrumentNumber\": \"SYNTHETIC-001\",\n    \"shortNarration\": null,\n    \"narration\": \"Synthetic receipt\",\n    \"ledger\": [\n      { \"account\": { \"code\": 301, \"name\": \"Cash\" }, \"debit\": 1500, \"credit\": 0 },\n      { \"account\": { \"code\": 7001, \"name\": \"Synthetic Traders\" }, \"debit\": 0, \"credit\": 1500 }\n    ]\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.receipts.create\",\n    \"requestId\": \"rq_0SYNTHET1C0000000000000201\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"allocationCount\": 2,\n    \"verification\": [\"busyReadBack\", \"savedRows\"],\n    \"elapsedMs\": 6410,\n    \"executedAt\": \"2026-10-16T10:05:00.0000000+05:30\"\n  }\n}"},{"id":"2111e797-ca73-14ec-0faa-649bbf416b54","name":"409 – duplicate receiptReference (details.receiptId; nothing written) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"receiptReference\": \"{{receiptReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"party\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"amount\": 100,\n  \"instrumentNumber\": \"SYNTHETIC-001\",\n  \"shortNarration\": \"Postman cloud test receipt\",\n  \"narration\": \"Postman cloud test receipt (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/receipt-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/receipt-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays receipts (Windows `0df569b` or later — **not** in public release 0.0.12; the development PC's installed candidate has it); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `receiptReference`, `date`, `account`, `party`, `amount` · **Optional:** `voucherSeries`, `allocations`, `instrumentNumber`, `shortNarration`, `narration` · operation `busy.receipts.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY receipt – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads): **one** cash-in-hand, bank or bank OD `account` receives `amount` from **one** `party`. **Create only**. **SQL Server companies with a SQL login, and Access companies** (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 64 KiB, else `413 REQUEST_TOO_LARGE`):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `receiptReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's receipts of the year |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `account`, `party` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`; the account must be cash in hand, bank or bank OD; the party neither |\n| `voucherSeries` | optional | needed when the company has more than one receipt series |\n| `amount` | yes | more than 0, at most 9999999999.99, at most 2 decimals |\n| `allocations` | optional | 1-100, only for a party BUSY keeps bill by bill: `{ \"bill\": { \"number\": \"…\" }, \"amount\": n }` (one of the party's own outstanding bills, never over-settled) or `{ \"newReference\": { \"number\": \"…\", \"dueDate\": \"YYYY-MM-DD\" }, \"amount\": n }` (a number new to the party; due date on or after `date`, at most five years later, default `date`); each number once; together at most `amount` — the rest stays on account |\n| `instrumentNumber`, `shortNarration`, `narration` | optional | 1-30, 1-40, 1-94 |\nNo instrument type; any other member is refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second receipt with the same `receiptReference` is refused `409 RECEIPT_REFERENCE_TAKEN` with `details.receiptId`; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the receipt up by `receiptReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back or a settled bill differs (`details.receiptId`, `details.mismatchedFields`): do not resend.\n\n**Other refusals:** `409 RECEIPT_NEW_REFERENCE_TAKEN`, `409 RECEIPT_MASTER_CHANGED`, `422 RECEIPT_ACCOUNT_UNSUPPORTED`, `422 RECEIPT_ALLOCATION_UNSUPPORTED`, `422 RECEIPT_BILL_NOT_FOUND`, `422 RECEIPT_BILL_OVERSETTLED`, `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `503 BUSY_COM_QUEUE_TIMEOUT` (the only retryable code).\n\n**Safe test guidance:** development-test company only (`COMP0002` / `2026`); set `receiptReference` to a new, unique test reference before each send; to settle a bill, add an `allocations` entry with a bill number the party owes (for example a test invoice's `billReference.number`). Test receipts stay in BUSY. The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000202"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"RECEIPT_REFERENCE_TAKEN\",\n      \"message\": \"A receipt of this company and financial year already holds this receiptReference. A create never changes an existing receipt; if your earlier call saved it, metadata.error.details.receiptId names it.\",\n      \"field\": \"receiptReference\",\n      \"details\": { \"receiptId\": 9201 }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000202\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"a6367746-d458-ec38-8697-af5efda71323","name":"400 – allocations add up to more than amount (refused by the cloud, nothing sent) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"receiptReference\": \"{{receiptReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"party\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"amount\": 100,\n  \"instrumentNumber\": \"SYNTHETIC-001\",\n  \"shortNarration\": \"Postman cloud test receipt\",\n  \"narration\": \"Postman cloud test receipt (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/receipt-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/receipt-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays receipts (Windows `0df569b` or later — **not** in public release 0.0.12; the development PC's installed candidate has it); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `receiptReference`, `date`, `account`, `party`, `amount` · **Optional:** `voucherSeries`, `allocations`, `instrumentNumber`, `shortNarration`, `narration` · operation `busy.receipts.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY receipt – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads): **one** cash-in-hand, bank or bank OD `account` receives `amount` from **one** `party`. **Create only**. **SQL Server companies with a SQL login, and Access companies** (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 64 KiB, else `413 REQUEST_TOO_LARGE`):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `receiptReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's receipts of the year |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `account`, `party` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`; the account must be cash in hand, bank or bank OD; the party neither |\n| `voucherSeries` | optional | needed when the company has more than one receipt series |\n| `amount` | yes | more than 0, at most 9999999999.99, at most 2 decimals |\n| `allocations` | optional | 1-100, only for a party BUSY keeps bill by bill: `{ \"bill\": { \"number\": \"…\" }, \"amount\": n }` (one of the party's own outstanding bills, never over-settled) or `{ \"newReference\": { \"number\": \"…\", \"dueDate\": \"YYYY-MM-DD\" }, \"amount\": n }` (a number new to the party; due date on or after `date`, at most five years later, default `date`); each number once; together at most `amount` — the rest stays on account |\n| `instrumentNumber`, `shortNarration`, `narration` | optional | 1-30, 1-40, 1-94 |\nNo instrument type; any other member is refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second receipt with the same `receiptReference` is refused `409 RECEIPT_REFERENCE_TAKEN` with `details.receiptId`; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the receipt up by `receiptReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back or a settled bill differs (`details.receiptId`, `details.mismatchedFields`): do not resend.\n\n**Other refusals:** `409 RECEIPT_NEW_REFERENCE_TAKEN`, `409 RECEIPT_MASTER_CHANGED`, `422 RECEIPT_ACCOUNT_UNSUPPORTED`, `422 RECEIPT_ALLOCATION_UNSUPPORTED`, `422 RECEIPT_BILL_NOT_FOUND`, `422 RECEIPT_BILL_OVERSETTLED`, `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `503 BUSY_COM_QUEUE_TIMEOUT` (the only retryable code).\n\n**Safe test guidance:** development-test company only (`COMP0002` / `2026`); set `receiptReference` to a new, unique test reference before each send; to settle a bill, add an `allocations` entry with a bill number the party owes (for example a test invoice's `billReference.number`). Test receipts stay in BUSY. The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"The allocations add up to more than amount. Allocate at most the amount received; the rest stays on account.\",\n      \"field\": \"allocations\"\n    },\n    \"requestId\": \"req_0SYNTHET1C0000000000000203\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"4a1c0db6-d131-95e2-4637-b574c09c77a5","name":"422 – RECEIPT_BILL_NOT_FOUND: not a bill this party owes (nothing written) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"receiptReference\": \"{{receiptReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"party\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"amount\": 100,\n  \"instrumentNumber\": \"SYNTHETIC-001\",\n  \"shortNarration\": \"Postman cloud test receipt\",\n  \"narration\": \"Postman cloud test receipt (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/receipt-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/receipt-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays receipts (Windows `0df569b` or later — **not** in public release 0.0.12; the development PC's installed candidate has it); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `receiptReference`, `date`, `account`, `party`, `amount` · **Optional:** `voucherSeries`, `allocations`, `instrumentNumber`, `shortNarration`, `narration` · operation `busy.receipts.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY receipt – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads): **one** cash-in-hand, bank or bank OD `account` receives `amount` from **one** `party`. **Create only**. **SQL Server companies with a SQL login, and Access companies** (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 64 KiB, else `413 REQUEST_TOO_LARGE`):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `receiptReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's receipts of the year |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `account`, `party` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`; the account must be cash in hand, bank or bank OD; the party neither |\n| `voucherSeries` | optional | needed when the company has more than one receipt series |\n| `amount` | yes | more than 0, at most 9999999999.99, at most 2 decimals |\n| `allocations` | optional | 1-100, only for a party BUSY keeps bill by bill: `{ \"bill\": { \"number\": \"…\" }, \"amount\": n }` (one of the party's own outstanding bills, never over-settled) or `{ \"newReference\": { \"number\": \"…\", \"dueDate\": \"YYYY-MM-DD\" }, \"amount\": n }` (a number new to the party; due date on or after `date`, at most five years later, default `date`); each number once; together at most `amount` — the rest stays on account |\n| `instrumentNumber`, `shortNarration`, `narration` | optional | 1-30, 1-40, 1-94 |\nNo instrument type; any other member is refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second receipt with the same `receiptReference` is refused `409 RECEIPT_REFERENCE_TAKEN` with `details.receiptId`; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the receipt up by `receiptReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back or a settled bill differs (`details.receiptId`, `details.mismatchedFields`): do not resend.\n\n**Other refusals:** `409 RECEIPT_NEW_REFERENCE_TAKEN`, `409 RECEIPT_MASTER_CHANGED`, `422 RECEIPT_ACCOUNT_UNSUPPORTED`, `422 RECEIPT_ALLOCATION_UNSUPPORTED`, `422 RECEIPT_BILL_NOT_FOUND`, `422 RECEIPT_BILL_OVERSETTLED`, `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `503 BUSY_COM_QUEUE_TIMEOUT` (the only retryable code).\n\n**Safe test guidance:** development-test company only (`COMP0002` / `2026`); set `receiptReference` to a new, unique test reference before each send; to settle a bill, add an `allocations` entry with a bill number the party owes (for example a test invoice's `billReference.number`). Test receipts stay in BUSY. The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000204"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"RECEIPT_BILL_NOT_FOUND\",\n      \"message\": \"This number is not an outstanding bill of the paying party in BUSY (a receivable it still owes). Check the bill's number, or send the amount as a new reference or leave it on account.\",\n      \"field\": \"allocations[0].bill.number\"\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000204\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"fccc33e4-cc8a-0ae5-9bd9-e0a9bec8c4cb","name":"502 – BUSY_WRITE_UNVERIFIED (saved, a settled bill differs; do not resend) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"receiptReference\": \"{{receiptReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"party\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"amount\": 100,\n  \"instrumentNumber\": \"SYNTHETIC-001\",\n  \"shortNarration\": \"Postman cloud test receipt\",\n  \"narration\": \"Postman cloud test receipt (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/receipt-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/receipt-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays receipts (Windows `0df569b` or later — **not** in public release 0.0.12; the development PC's installed candidate has it); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `receiptReference`, `date`, `account`, `party`, `amount` · **Optional:** `voucherSeries`, `allocations`, `instrumentNumber`, `shortNarration`, `narration` · operation `busy.receipts.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY receipt – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads): **one** cash-in-hand, bank or bank OD `account` receives `amount` from **one** `party`. **Create only**. **SQL Server companies with a SQL login, and Access companies** (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 64 KiB, else `413 REQUEST_TOO_LARGE`):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `receiptReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's receipts of the year |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `account`, `party` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`; the account must be cash in hand, bank or bank OD; the party neither |\n| `voucherSeries` | optional | needed when the company has more than one receipt series |\n| `amount` | yes | more than 0, at most 9999999999.99, at most 2 decimals |\n| `allocations` | optional | 1-100, only for a party BUSY keeps bill by bill: `{ \"bill\": { \"number\": \"…\" }, \"amount\": n }` (one of the party's own outstanding bills, never over-settled) or `{ \"newReference\": { \"number\": \"…\", \"dueDate\": \"YYYY-MM-DD\" }, \"amount\": n }` (a number new to the party; due date on or after `date`, at most five years later, default `date`); each number once; together at most `amount` — the rest stays on account |\n| `instrumentNumber`, `shortNarration`, `narration` | optional | 1-30, 1-40, 1-94 |\nNo instrument type; any other member is refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second receipt with the same `receiptReference` is refused `409 RECEIPT_REFERENCE_TAKEN` with `details.receiptId`; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the receipt up by `receiptReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back or a settled bill differs (`details.receiptId`, `details.mismatchedFields`): do not resend.\n\n**Other refusals:** `409 RECEIPT_NEW_REFERENCE_TAKEN`, `409 RECEIPT_MASTER_CHANGED`, `422 RECEIPT_ACCOUNT_UNSUPPORTED`, `422 RECEIPT_ALLOCATION_UNSUPPORTED`, `422 RECEIPT_BILL_NOT_FOUND`, `422 RECEIPT_BILL_OVERSETTLED`, `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `503 BUSY_COM_QUEUE_TIMEOUT` (the only retryable code).\n\n**Safe test guidance:** development-test company only (`COMP0002` / `2026`); set `receiptReference` to a new, unique test reference before each send; to settle a bill, add an `allocations` entry with a bill number the party owes (for example a test invoice's `billReference.number`). Test receipts stay in BUSY. The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000205"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNVERIFIED\",\n      \"message\": \"BUSY saved the receipt, but its read-back or a bill it settles differs from the request in the fields listed in metadata.error.details.mismatchedFields. The receipt is in BUSY; check it there and do not send it again.\",\n      \"details\": { \"receiptId\": 9202, \"mismatchedFields\": [\"allocations[0]\", \"saved.ledger\"] }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000205\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"9cae15e4-c6c1-7df5-6703-dab5ad117af3","name":"504 – BUSY_WRITE_UNCERTAIN, reconciled found: key kept, do not resend [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"receiptReference\": \"{{receiptReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"party\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"amount\": 100,\n  \"instrumentNumber\": \"SYNTHETIC-001\",\n  \"shortNarration\": \"Postman cloud test receipt\",\n  \"narration\": \"Postman cloud test receipt (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/receipt-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/receipt-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays receipts (Windows `0df569b` or later — **not** in public release 0.0.12; the development PC's installed candidate has it); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `receiptReference`, `date`, `account`, `party`, `amount` · **Optional:** `voucherSeries`, `allocations`, `instrumentNumber`, `shortNarration`, `narration` · operation `busy.receipts.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY receipt – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads): **one** cash-in-hand, bank or bank OD `account` receives `amount` from **one** `party`. **Create only**. **SQL Server companies with a SQL login, and Access companies** (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 64 KiB, else `413 REQUEST_TOO_LARGE`):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `receiptReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's receipts of the year |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `account`, `party` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }`; the account must be cash in hand, bank or bank OD; the party neither |\n| `voucherSeries` | optional | needed when the company has more than one receipt series |\n| `amount` | yes | more than 0, at most 9999999999.99, at most 2 decimals |\n| `allocations` | optional | 1-100, only for a party BUSY keeps bill by bill: `{ \"bill\": { \"number\": \"…\" }, \"amount\": n }` (one of the party's own outstanding bills, never over-settled) or `{ \"newReference\": { \"number\": \"…\", \"dueDate\": \"YYYY-MM-DD\" }, \"amount\": n }` (a number new to the party; due date on or after `date`, at most five years later, default `date`); each number once; together at most `amount` — the rest stays on account |\n| `instrumentNumber`, `shortNarration`, `narration` | optional | 1-30, 1-40, 1-94 |\nNo instrument type; any other member is refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second receipt with the same `receiptReference` is refused `409 RECEIPT_REFERENCE_TAKEN` with `details.receiptId`; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the receipt up by `receiptReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back or a settled bill differs (`details.receiptId`, `details.mismatchedFields`): do not resend.\n\n**Other refusals:** `409 RECEIPT_NEW_REFERENCE_TAKEN`, `409 RECEIPT_MASTER_CHANGED`, `422 RECEIPT_ACCOUNT_UNSUPPORTED`, `422 RECEIPT_ALLOCATION_UNSUPPORTED`, `422 RECEIPT_BILL_NOT_FOUND`, `422 RECEIPT_BILL_OVERSETTLED`, `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `503 BUSY_COM_QUEUE_TIMEOUT` (the only retryable code).\n\n**Safe test guidance:** development-test company only (`COMP0002` / `2026`); set `receiptReference` to a new, unique test reference before each send; to settle a bill, add an `allocations` entry with a bill number the party owes (for example a test invoice's `billReference.number`). Test receipts stay in BUSY. The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000206","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"BUSY stopped while saving the receipt; a receipt with this receiptReference exists now (metadata.error.details.receiptId). Check it in BUSY; do not send it again.\",\n      \"details\": { \"receiptId\": 9203, \"reconciliation\": \"found\" }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000206\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"15b2992c-34e2-ecbf-beb2-93ffd2aaee70"},{"name":"⚠ BUSY sales return – create (writes to BUSY)","id":"5e426014-a09a-0962-d255-c7149c0df2c4","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 150, \"description\": [\"Postman cloud test return\"] }\n  ],\n  \"narration\": \"Postman cloud test sales return (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-return-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/sales-return-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)\n<strong>Status (2026-10-23):</strong> deployed and live (release <code>790395a</code>). The PC needs an AI Zeny version that relays sales returns (Windows <code>5594826</code> or later — <strong>not</strong> in public release 0.0.12; the development PC's installed candidate has it); an earlier version answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>returnReference</code>, <code>date</code>, <code>customer</code>, <code>saleType</code>, <code>materialCenter</code>, <code>lines</code> · <strong>Optional:</strong> <code>voucherSeries</code>, <code>originalInvoice</code>, <code>adjustment</code>, <code>narration</code> · operation <code>busy.sales-returns.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.</strong> Same operation, body and answer as the Local request <em>Local PC → ⚠ Voucher Create → ⚠ BUSY sales return – create</em>, called through the Cloud Relay with the organization's cloud token (the same token that reads): a <strong>sales return (credit note)</strong>, the reverse of a sale — the customer is credited, sales and GST debited, the goods come back into <code>materialCenter</code>. <strong>Create only</strong>. <strong>SQL Server companies with a SQL login, and Access companies</strong> (Windows <code>6c5776d</code> or later; an earlier PC answers Access with <code>409 MASTER_WRITE_PROVIDER_UNSUPPORTED</code>). Never run it from scripts or a collection run.</p>\n<p><strong>Body</strong> (at most 128 KiB, else <code>413 REQUEST_TOO_LARGE</code>; the PC also accepts at most 64 KiB per signed command, so very long lines may be refused <code>413</code> before anything is recorded or sent):</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Required</th>\n<th>Rule</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>companyCode</code>, <code>financialYear</code></td>\n<td>yes</td>\n<td>one company and one four-digit starting year within the token's scope</td>\n</tr>\n<tr>\n<td><code>returnReference</code></td>\n<td>yes</td>\n<td>your own reference, 1-60 characters (trimmed); unique among the company's sales returns of the year (BUSY's own included)</td>\n</tr>\n<tr>\n<td><code>date</code></td>\n<td>yes</td>\n<td><code>YYYY-MM-DD</code>, inside the financial year</td>\n</tr>\n<tr>\n<td><code>customer</code>, <code>saleType</code>, <code>materialCenter</code></td>\n<td>yes</td>\n<td><code>{ \"code\": n }</code> or <code>{ \"name\": \"…\" }</code></td>\n</tr>\n<tr>\n<td><code>voucherSeries</code></td>\n<td>optional</td>\n<td>needed when the company has more than one sales-return series</td>\n</tr>\n<tr>\n<td><code>lines</code></td>\n<td>yes</td>\n<td>1-100, the sales invoice's line rules with <strong>quantity at most 2 decimals</strong></td>\n</tr>\n<tr>\n<td><code>originalInvoice</code></td>\n<td>optional</td>\n<td><code>{ \"voucherId\": n }</code> or <code>{ \"number\": \"…\" }</code>: the customer's own, non-cancelled sales invoice of the year, dated on or before the return; no item comes back beyond what it sold less earlier returns</td>\n</tr>\n<tr>\n<td><code>adjustment</code></td>\n<td>optional (on account)</td>\n<td><code>{ \"type\": \"onAccount\" }</code>, <code>{ \"type\": \"againstOriginalInvoice\", \"amount\"?: n }</code> (needs <code>originalInvoice</code>; never over-settles its bill) or <code>{ \"type\": \"newReference\", \"number\": \"…\", \"dueDate\"?: \"…\", \"amount\"?: n }</code>; only for a customer kept bill by bill</td>\n</tr>\n<tr>\n<td><code>narration</code></td>\n<td>optional</td>\n<td>1-94</td>\n</tr>\n<tr>\n<td>No billing block, return number, amount or total; any other member is refused (<code>400 BAD_REQUEST</code>).</td>\n<td></td>\n<td></td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Duplicates and unknown outcomes.</strong> A second return with the same <code>returnReference</code> is refused <code>409 SALES_RETURN_REFERENCE_TAKEN</code> with <code>details.returnId</code>; nothing is written. After <code>504 WRITE_RESULT_UNKNOWN</code> or <code>504 BUSY_WRITE_UNCERTAIN</code> do not resend blind and never with a new reference: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Look the return up by <code>returnReference</code>; to recover deliberately, unset <code>cloudIdempotencyKey</code> and resend the <strong>same</strong> body. <code>502 BUSY_WRITE_UNVERIFIED</code> = saved but the read-back or an adjusted bill differs (<code>details.returnId</code>, <code>details.mismatchedFields</code>): do not resend.</p>\n<p><strong>Other refusals:</strong> <code>404 SALES_RETURN_ORIGINAL_NOT_FOUND</code>; <code>422 SALES_RETURN_ORIGINAL_MISMATCH</code> / <code>_CANCELLED</code> / <code>_AMBIGUOUS</code> / <code>SALES_RETURN_HISTORY_AMBIGUOUS</code> / <code>_DATE_BEFORE_ORIGINAL</code> / <code>_SALE_TYPE_MISMATCH</code> / <code>_QUANTITY_EXCEEDS_SALE</code> / <code>_SALE_TYPE_UNSUPPORTED</code> / <code>_TAX_UNSUPPORTED</code> / <code>_ITEM_UNSUPPORTED</code> / <code>_ADJUSTMENT_UNSUPPORTED</code> / <code>_BILL_NOT_FOUND</code> / <code>_BILL_OVERSETTLED</code>; <code>409 SALES_RETURN_NEW_REFERENCE_TAKEN</code>, <code>409 SALES_RETURN_MASTER_CHANGED</code>; <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (the only retryable code).</p>\n<p><strong>Safe test guidance:</strong> development-test company only (<code>COMP0002</code> / <code>2026</code>); set <code>returnReference</code> to a new, unique test reference before each send; to return against an invoice, add <code>\"originalInvoice\": { \"voucherId\": {{salesInvoiceId}} }</code> and <code>\"adjustment\": { \"type\": \"againstOriginalInvoice\" }</code>. Test returns stay in BUSY. The examples are synthetic.</p>\n<p><strong>Durable queue:</strong> optional strict <code>queue</code> (omitted or <code>false</code>: synchronous; <code>true</code>: a <code>202</code> job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.</p>\n<hr />\n<p><strong>Parity update (2026-10-23, deployed in release <code>790395a</code>; the PC must be Windows <code>6c5776d</code> or later for these members).</strong> This request's body sends only the basic members. New optional members and codes:</p>\n<ul>\n<li><code>queue</code> (optional, <code>true</code> or <code>false</code>, default <code>false</code>; <code>null</code> is refused <code>400</code>): with <code>true</code> the PC accepts the write on its durable queue and the answer is <strong><code>202</code></strong> with <code>data: null</code> and <code>metadata.queued: true</code>, <code>metadata.jobId</code> (32 hex), <code>metadata.status</code> — acceptance, <strong>not</strong> a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable <code>companyCode</code>/four-digit <code>financialYear</code>; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (<code>202</code>) and fails there. The cloud sends it once.</li>\n<li>GST modes: <code>taxCalculation</code> (<code>auto</code> default, or <code>manual</code>) and <code>pricingMode</code> (<code>gstExclusive</code> default, or <code>gstInclusive</code>, which must match the voucher type's inclusive flag). Manual needs every line's <code>amounts { taxableAmount, cgst, sgst, igst, amount }</code> and the voucher <code>totals</code> (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: <code>422 GST_AMOUNTS_INVALID</code>, <code>422 GST_MODE_UNSUPPORTED</code>, <code>409 GST_CONFIGURATION_CHANGED</code>. A new mode with <code>originalInvoice</code> is <code>422 GST_MODE_UNSUPPORTED</code>.</li>\n<li><code>salesman</code> (optional): <code>{ \"code\": n }</code> or <code>{ \"name\": \"…\" }</code>; omitted or <code>null</code> keeps BUSY's default. Codes: <code>409 SALESMAN_CONFIGURATION_UNSUPPORTED</code>, <code>409 SALESMAN_CONFIGURATION_CHANGED</code>.</li>\n<li>Line <code>description</code>: 1-10 positions of at most 40 characters (<code>null</code> or empty keeps a position empty; at least one holds text); the series must allow that many lines (<code>422 DESCRIPTION_LINE_NOT_ALLOWED</code>). <code>422 SALES_RETURN_SERIES_UNSUPPORTED</code>.</li>\n<li>Shared refusals of every write, answered before anything is written: <code>403 PLAN_FEATURE_NOT_INCLUDED</code>, <code>409 PLAN_NOT_KNOWN</code>, <code>503 BUSY_COM_RECOVERY_REQUIRED</code>, <code>409 BUSY_WRITE_TARGET_CHANGED</code>, <code>422 BUSY_SETTING_REQUIRED</code>, <code>502 BUSY_SETTINGS_UNREADABLE</code>; queue refusals <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>, <code>503 WRITE_QUEUE_UNAVAILABLE</code>.</li>\n</ul>\n<p>Scenario requests for the new members are in this folder, named <code>⚠ Scenario – …</code> and <code>⚠ EXPECTED REFUSAL …</code>; they are guarded like this one (<code>confirmMutating</code> = <code>yes</code>, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Cloud Relay has not deployed the new numbering schema; these are documentation examples only. Do not Send until Cloud parity is deployed and verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 150,\n      \"description\": [\n        \"Postman cloud test return\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman cloud test sales return (on account)\",\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"customer\": {\n    \"name\": \"AZPOC-SI CUST MP\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 150,\n      \"description\": [\n        \"Postman cloud test return\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman cloud test sales return (on account)\",\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","urlObject":{"path":["v1","sales-return-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"77c0ab62-4829-dcf1-0e65-b02d78d5803b","name":"200 – return against its invoice, bill reduced [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 150, \"description\": [\"Postman cloud test return\"] }\n  ],\n  \"narration\": \"Postman cloud test sales return (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-return-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-return-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays sales returns (Windows `5594826` or later — **not** in public release 0.0.12; the development PC's installed candidate has it); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalInvoice`, `adjustment`, `narration` · operation `busy.sales-returns.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales return – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads): a **sales return (credit note)**, the reverse of a sale — the customer is credited, sales and GST debited, the goods come back into `materialCenter`. **Create only**. **SQL Server companies with a SQL login, and Access companies** (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 128 KiB, else `413 REQUEST_TOO_LARGE`; the PC also accepts at most 64 KiB per signed command, so very long lines may be refused `413` before anything is recorded or sent):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `returnReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's sales returns of the year (BUSY's own included) |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }` |\n| `voucherSeries` | optional | needed when the company has more than one sales-return series |\n| `lines` | yes | 1-100, the sales invoice's line rules with **quantity at most 2 decimals** |\n| `originalInvoice` | optional | `{ \"voucherId\": n }` or `{ \"number\": \"…\" }`: the customer's own, non-cancelled sales invoice of the year, dated on or before the return; no item comes back beyond what it sold less earlier returns |\n| `adjustment` | optional (on account) | `{ \"type\": \"onAccount\" }`, `{ \"type\": \"againstOriginalInvoice\", \"amount\"?: n }` (needs `originalInvoice`; never over-settles its bill) or `{ \"type\": \"newReference\", \"number\": \"…\", \"dueDate\"?: \"…\", \"amount\"?: n }`; only for a customer kept bill by bill |\n| `narration` | optional | 1-94 |\nNo billing block, return number, amount or total; any other member is refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second return with the same `returnReference` is refused `409 SALES_RETURN_REFERENCE_TAKEN` with `details.returnId`; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the return up by `returnReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back or an adjusted bill differs (`details.returnId`, `details.mismatchedFields`): do not resend.\n\n**Other refusals:** `404 SALES_RETURN_ORIGINAL_NOT_FOUND`; `422 SALES_RETURN_ORIGINAL_MISMATCH` / `_CANCELLED` / `_AMBIGUOUS` / `SALES_RETURN_HISTORY_AMBIGUOUS` / `_DATE_BEFORE_ORIGINAL` / `_SALE_TYPE_MISMATCH` / `_QUANTITY_EXCEEDS_SALE` / `_SALE_TYPE_UNSUPPORTED` / `_TAX_UNSUPPORTED` / `_ITEM_UNSUPPORTED` / `_ADJUSTMENT_UNSUPPORTED` / `_BILL_NOT_FOUND` / `_BILL_OVERSETTLED`; `409 SALES_RETURN_NEW_REFERENCE_TAKEN`, `409 SALES_RETURN_MASTER_CHANGED`; `503 BUSY_COM_QUEUE_TIMEOUT` (the only retryable code).\n\n**Safe test guidance:** development-test company only (`COMP0002` / `2026`); set `returnReference` to a new, unique test reference before each send; to return against an invoice, add `\"originalInvoice\": { \"voucherId\": {{salesInvoiceId}} }` and `\"adjustment\": { \"type\": \"againstOriginalInvoice\" }`. Test returns stay in BUSY. The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `originalInvoice` is `422 GST_MODE_UNSUPPORTED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_RETURN_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000301"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"returnId\": 9301,\n    \"returnNumber\": \"SR-7\",\n    \"returnReference\": \"SR-SYNTH-0001\",\n    \"date\": \"2026-10-16\",\n    \"voucherSeries\": { \"code\": 264, \"name\": \"Main\" },\n    \"customer\": { \"code\": 7001, \"name\": \"Synthetic Traders\" },\n    \"saleType\": { \"code\": 1223, \"name\": \"Local-ItemWise\" },\n    \"taxation\": \"local\",\n    \"materialCenter\": { \"code\": 201, \"name\": \"Main Store\" },\n    \"originalInvoice\": { \"voucherId\": 9101, \"number\": \"INV-31\", \"date\": \"2026-10-16\" },\n    \"lines\": [\n      { \"lineNumber\": 1, \"item\": { \"code\": 9401, \"name\": \"Synthetic Item\" }, \"unit\": \"Pcs.\", \"quantity\": 1, \"rate\": 150, \"discountPercent\": 10, \"netRate\": 135, \"taxableAmount\": 135, \"cgst\": 8.1, \"sgst\": 8.1, \"igst\": 0, \"taxAmount\": 16.2, \"amount\": 151.2, \"mrp\": 180, \"description\": [] }\n    ],\n    \"totals\": { \"quantity\": 1, \"taxableAmount\": 135, \"cgst\": 8.1, \"sgst\": 8.1, \"igst\": 0, \"taxAmount\": 16.2, \"amount\": 151.2 },\n    \"adjustment\": { \"type\": \"againstOriginalInvoice\", \"number\": \"INV-31\", \"amount\": 151.2, \"dueDate\": \"2026-11-15\", \"outstandingBefore\": 302.4, \"outstandingAfter\": 151.2 },\n    \"unallocatedAmount\": 0,\n    \"narration\": \"Synthetic return\",\n    \"ledger\": [\n      { \"account\": { \"code\": 501, \"name\": \"Sales\" }, \"debit\": 135, \"credit\": 0 },\n      { \"account\": { \"code\": 611, \"name\": \"CGST Output\" }, \"debit\": 8.1, \"credit\": 0 },\n      { \"account\": { \"code\": 612, \"name\": \"SGST Output\" }, \"debit\": 8.1, \"credit\": 0 },\n      { \"account\": { \"code\": 7001, \"name\": \"Synthetic Traders\" }, \"debit\": 0, \"credit\": 151.2 }\n    ]\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.sales-returns.create\",\n    \"requestId\": \"rq_0SYNTHET1C0000000000000301\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 1,\n    \"verification\": [\"busyReadBack\", \"savedRows\"],\n    \"elapsedMs\": 7310,\n    \"executedAt\": \"2026-10-16T10:10:00.0000000+05:30\"\n  }\n}"},{"id":"88471860-7a1e-124a-f7a4-a5cdab6377fa","name":"409 – duplicate returnReference (details.returnId; nothing written) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 150, \"description\": [\"Postman cloud test return\"] }\n  ],\n  \"narration\": \"Postman cloud test sales return (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-return-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-return-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays sales returns (Windows `5594826` or later — **not** in public release 0.0.12; the development PC's installed candidate has it); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalInvoice`, `adjustment`, `narration` · operation `busy.sales-returns.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales return – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads): a **sales return (credit note)**, the reverse of a sale — the customer is credited, sales and GST debited, the goods come back into `materialCenter`. **Create only**. **SQL Server companies with a SQL login, and Access companies** (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 128 KiB, else `413 REQUEST_TOO_LARGE`; the PC also accepts at most 64 KiB per signed command, so very long lines may be refused `413` before anything is recorded or sent):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `returnReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's sales returns of the year (BUSY's own included) |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }` |\n| `voucherSeries` | optional | needed when the company has more than one sales-return series |\n| `lines` | yes | 1-100, the sales invoice's line rules with **quantity at most 2 decimals** |\n| `originalInvoice` | optional | `{ \"voucherId\": n }` or `{ \"number\": \"…\" }`: the customer's own, non-cancelled sales invoice of the year, dated on or before the return; no item comes back beyond what it sold less earlier returns |\n| `adjustment` | optional (on account) | `{ \"type\": \"onAccount\" }`, `{ \"type\": \"againstOriginalInvoice\", \"amount\"?: n }` (needs `originalInvoice`; never over-settles its bill) or `{ \"type\": \"newReference\", \"number\": \"…\", \"dueDate\"?: \"…\", \"amount\"?: n }`; only for a customer kept bill by bill |\n| `narration` | optional | 1-94 |\nNo billing block, return number, amount or total; any other member is refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second return with the same `returnReference` is refused `409 SALES_RETURN_REFERENCE_TAKEN` with `details.returnId`; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the return up by `returnReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back or an adjusted bill differs (`details.returnId`, `details.mismatchedFields`): do not resend.\n\n**Other refusals:** `404 SALES_RETURN_ORIGINAL_NOT_FOUND`; `422 SALES_RETURN_ORIGINAL_MISMATCH` / `_CANCELLED` / `_AMBIGUOUS` / `SALES_RETURN_HISTORY_AMBIGUOUS` / `_DATE_BEFORE_ORIGINAL` / `_SALE_TYPE_MISMATCH` / `_QUANTITY_EXCEEDS_SALE` / `_SALE_TYPE_UNSUPPORTED` / `_TAX_UNSUPPORTED` / `_ITEM_UNSUPPORTED` / `_ADJUSTMENT_UNSUPPORTED` / `_BILL_NOT_FOUND` / `_BILL_OVERSETTLED`; `409 SALES_RETURN_NEW_REFERENCE_TAKEN`, `409 SALES_RETURN_MASTER_CHANGED`; `503 BUSY_COM_QUEUE_TIMEOUT` (the only retryable code).\n\n**Safe test guidance:** development-test company only (`COMP0002` / `2026`); set `returnReference` to a new, unique test reference before each send; to return against an invoice, add `\"originalInvoice\": { \"voucherId\": {{salesInvoiceId}} }` and `\"adjustment\": { \"type\": \"againstOriginalInvoice\" }`. Test returns stay in BUSY. The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `originalInvoice` is `422 GST_MODE_UNSUPPORTED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_RETURN_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000302"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SALES_RETURN_REFERENCE_TAKEN\",\n      \"message\": \"A sales return of this company and financial year already holds this returnReference. A create never changes an existing return; if your earlier call saved it, metadata.error.details.returnId names it.\",\n      \"field\": \"returnReference\",\n      \"details\": { \"returnId\": 9301 }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000302\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"83651fbd-6aba-0ece-9704-5539dacf775b","name":"400 – quantity with 3 decimals (refused by the cloud, nothing sent) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 150, \"description\": [\"Postman cloud test return\"] }\n  ],\n  \"narration\": \"Postman cloud test sales return (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-return-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-return-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays sales returns (Windows `5594826` or later — **not** in public release 0.0.12; the development PC's installed candidate has it); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalInvoice`, `adjustment`, `narration` · operation `busy.sales-returns.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales return – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads): a **sales return (credit note)**, the reverse of a sale — the customer is credited, sales and GST debited, the goods come back into `materialCenter`. **Create only**. **SQL Server companies with a SQL login, and Access companies** (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 128 KiB, else `413 REQUEST_TOO_LARGE`; the PC also accepts at most 64 KiB per signed command, so very long lines may be refused `413` before anything is recorded or sent):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `returnReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's sales returns of the year (BUSY's own included) |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }` |\n| `voucherSeries` | optional | needed when the company has more than one sales-return series |\n| `lines` | yes | 1-100, the sales invoice's line rules with **quantity at most 2 decimals** |\n| `originalInvoice` | optional | `{ \"voucherId\": n }` or `{ \"number\": \"…\" }`: the customer's own, non-cancelled sales invoice of the year, dated on or before the return; no item comes back beyond what it sold less earlier returns |\n| `adjustment` | optional (on account) | `{ \"type\": \"onAccount\" }`, `{ \"type\": \"againstOriginalInvoice\", \"amount\"?: n }` (needs `originalInvoice`; never over-settles its bill) or `{ \"type\": \"newReference\", \"number\": \"…\", \"dueDate\"?: \"…\", \"amount\"?: n }`; only for a customer kept bill by bill |\n| `narration` | optional | 1-94 |\nNo billing block, return number, amount or total; any other member is refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second return with the same `returnReference` is refused `409 SALES_RETURN_REFERENCE_TAKEN` with `details.returnId`; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the return up by `returnReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back or an adjusted bill differs (`details.returnId`, `details.mismatchedFields`): do not resend.\n\n**Other refusals:** `404 SALES_RETURN_ORIGINAL_NOT_FOUND`; `422 SALES_RETURN_ORIGINAL_MISMATCH` / `_CANCELLED` / `_AMBIGUOUS` / `SALES_RETURN_HISTORY_AMBIGUOUS` / `_DATE_BEFORE_ORIGINAL` / `_SALE_TYPE_MISMATCH` / `_QUANTITY_EXCEEDS_SALE` / `_SALE_TYPE_UNSUPPORTED` / `_TAX_UNSUPPORTED` / `_ITEM_UNSUPPORTED` / `_ADJUSTMENT_UNSUPPORTED` / `_BILL_NOT_FOUND` / `_BILL_OVERSETTLED`; `409 SALES_RETURN_NEW_REFERENCE_TAKEN`, `409 SALES_RETURN_MASTER_CHANGED`; `503 BUSY_COM_QUEUE_TIMEOUT` (the only retryable code).\n\n**Safe test guidance:** development-test company only (`COMP0002` / `2026`); set `returnReference` to a new, unique test reference before each send; to return against an invoice, add `\"originalInvoice\": { \"voucherId\": {{salesInvoiceId}} }` and `\"adjustment\": { \"type\": \"againstOriginalInvoice\" }`. Test returns stay in BUSY. The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `originalInvoice` is `422 GST_MODE_UNSUPPORTED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_RETURN_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"lines[0].quantity must have at most 2 decimals: BUSY keeps a sales return's quantity to 2 decimals.\",\n      \"field\": \"lines[0].quantity\"\n    },\n    \"requestId\": \"req_0SYNTHET1C0000000000000303\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"e07ad52e-b7b3-5a2a-6048-84859dfd17f2","name":"422 – SALES_RETURN_QUANTITY_EXCEEDS_SALE (more than sold less earlier returns; nothing written) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 150, \"description\": [\"Postman cloud test return\"] }\n  ],\n  \"narration\": \"Postman cloud test sales return (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-return-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-return-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays sales returns (Windows `5594826` or later — **not** in public release 0.0.12; the development PC's installed candidate has it); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalInvoice`, `adjustment`, `narration` · operation `busy.sales-returns.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales return – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads): a **sales return (credit note)**, the reverse of a sale — the customer is credited, sales and GST debited, the goods come back into `materialCenter`. **Create only**. **SQL Server companies with a SQL login, and Access companies** (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 128 KiB, else `413 REQUEST_TOO_LARGE`; the PC also accepts at most 64 KiB per signed command, so very long lines may be refused `413` before anything is recorded or sent):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `returnReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's sales returns of the year (BUSY's own included) |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }` |\n| `voucherSeries` | optional | needed when the company has more than one sales-return series |\n| `lines` | yes | 1-100, the sales invoice's line rules with **quantity at most 2 decimals** |\n| `originalInvoice` | optional | `{ \"voucherId\": n }` or `{ \"number\": \"…\" }`: the customer's own, non-cancelled sales invoice of the year, dated on or before the return; no item comes back beyond what it sold less earlier returns |\n| `adjustment` | optional (on account) | `{ \"type\": \"onAccount\" }`, `{ \"type\": \"againstOriginalInvoice\", \"amount\"?: n }` (needs `originalInvoice`; never over-settles its bill) or `{ \"type\": \"newReference\", \"number\": \"…\", \"dueDate\"?: \"…\", \"amount\"?: n }`; only for a customer kept bill by bill |\n| `narration` | optional | 1-94 |\nNo billing block, return number, amount or total; any other member is refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second return with the same `returnReference` is refused `409 SALES_RETURN_REFERENCE_TAKEN` with `details.returnId`; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the return up by `returnReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back or an adjusted bill differs (`details.returnId`, `details.mismatchedFields`): do not resend.\n\n**Other refusals:** `404 SALES_RETURN_ORIGINAL_NOT_FOUND`; `422 SALES_RETURN_ORIGINAL_MISMATCH` / `_CANCELLED` / `_AMBIGUOUS` / `SALES_RETURN_HISTORY_AMBIGUOUS` / `_DATE_BEFORE_ORIGINAL` / `_SALE_TYPE_MISMATCH` / `_QUANTITY_EXCEEDS_SALE` / `_SALE_TYPE_UNSUPPORTED` / `_TAX_UNSUPPORTED` / `_ITEM_UNSUPPORTED` / `_ADJUSTMENT_UNSUPPORTED` / `_BILL_NOT_FOUND` / `_BILL_OVERSETTLED`; `409 SALES_RETURN_NEW_REFERENCE_TAKEN`, `409 SALES_RETURN_MASTER_CHANGED`; `503 BUSY_COM_QUEUE_TIMEOUT` (the only retryable code).\n\n**Safe test guidance:** development-test company only (`COMP0002` / `2026`); set `returnReference` to a new, unique test reference before each send; to return against an invoice, add `\"originalInvoice\": { \"voucherId\": {{salesInvoiceId}} }` and `\"adjustment\": { \"type\": \"againstOriginalInvoice\" }`. Test returns stay in BUSY. The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `originalInvoice` is `422 GST_MODE_UNSUPPORTED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_RETURN_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000304"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"SALES_RETURN_QUANTITY_EXCEEDS_SALE\",\n      \"message\": \"The quantity is more than the original invoice sold of this item less its earlier sales returns in BUSY. Return at most the quantity still returnable.\",\n      \"field\": \"lines[0].quantity\"\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000304\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"95531b5e-cc0e-82c2-35a4-0e9105ea53a1","name":"502 – BUSY_WRITE_UNVERIFIED (saved, an adjusted bill differs; do not resend) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 150, \"description\": [\"Postman cloud test return\"] }\n  ],\n  \"narration\": \"Postman cloud test sales return (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-return-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-return-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays sales returns (Windows `5594826` or later — **not** in public release 0.0.12; the development PC's installed candidate has it); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalInvoice`, `adjustment`, `narration` · operation `busy.sales-returns.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales return – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads): a **sales return (credit note)**, the reverse of a sale — the customer is credited, sales and GST debited, the goods come back into `materialCenter`. **Create only**. **SQL Server companies with a SQL login, and Access companies** (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 128 KiB, else `413 REQUEST_TOO_LARGE`; the PC also accepts at most 64 KiB per signed command, so very long lines may be refused `413` before anything is recorded or sent):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `returnReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's sales returns of the year (BUSY's own included) |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }` |\n| `voucherSeries` | optional | needed when the company has more than one sales-return series |\n| `lines` | yes | 1-100, the sales invoice's line rules with **quantity at most 2 decimals** |\n| `originalInvoice` | optional | `{ \"voucherId\": n }` or `{ \"number\": \"…\" }`: the customer's own, non-cancelled sales invoice of the year, dated on or before the return; no item comes back beyond what it sold less earlier returns |\n| `adjustment` | optional (on account) | `{ \"type\": \"onAccount\" }`, `{ \"type\": \"againstOriginalInvoice\", \"amount\"?: n }` (needs `originalInvoice`; never over-settles its bill) or `{ \"type\": \"newReference\", \"number\": \"…\", \"dueDate\"?: \"…\", \"amount\"?: n }`; only for a customer kept bill by bill |\n| `narration` | optional | 1-94 |\nNo billing block, return number, amount or total; any other member is refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second return with the same `returnReference` is refused `409 SALES_RETURN_REFERENCE_TAKEN` with `details.returnId`; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the return up by `returnReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back or an adjusted bill differs (`details.returnId`, `details.mismatchedFields`): do not resend.\n\n**Other refusals:** `404 SALES_RETURN_ORIGINAL_NOT_FOUND`; `422 SALES_RETURN_ORIGINAL_MISMATCH` / `_CANCELLED` / `_AMBIGUOUS` / `SALES_RETURN_HISTORY_AMBIGUOUS` / `_DATE_BEFORE_ORIGINAL` / `_SALE_TYPE_MISMATCH` / `_QUANTITY_EXCEEDS_SALE` / `_SALE_TYPE_UNSUPPORTED` / `_TAX_UNSUPPORTED` / `_ITEM_UNSUPPORTED` / `_ADJUSTMENT_UNSUPPORTED` / `_BILL_NOT_FOUND` / `_BILL_OVERSETTLED`; `409 SALES_RETURN_NEW_REFERENCE_TAKEN`, `409 SALES_RETURN_MASTER_CHANGED`; `503 BUSY_COM_QUEUE_TIMEOUT` (the only retryable code).\n\n**Safe test guidance:** development-test company only (`COMP0002` / `2026`); set `returnReference` to a new, unique test reference before each send; to return against an invoice, add `\"originalInvoice\": { \"voucherId\": {{salesInvoiceId}} }` and `\"adjustment\": { \"type\": \"againstOriginalInvoice\" }`. Test returns stay in BUSY. The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `originalInvoice` is `422 GST_MODE_UNSUPPORTED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_RETURN_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000305"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNVERIFIED\",\n      \"message\": \"BUSY saved the sales return, but its read-back or a bill it adjusts differs from the request in the fields listed in metadata.error.details.mismatchedFields. The return is in BUSY; check it there and do not send it again.\",\n      \"details\": { \"returnId\": 9302, \"mismatchedFields\": [\"adjustment.bill\", \"saved.lines[0]\"] }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000305\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"814e8525-f510-387f-9a8d-ccb0b8b0cd2f","name":"504 – WRITE_RESULT_UNKNOWN (PC's answer lost): key kept, do not resend blind [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{returnReference}}\",\n  \"date\": \"2026-10-16\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"customer\": { \"name\": \"AZPOC-SI CUST MP\" },\n  \"saleType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 150, \"description\": [\"Postman cloud test return\"] }\n  ],\n  \"narration\": \"Postman cloud test sales return (on account)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-return-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/sales-return-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays sales returns (Windows `5594826` or later — **not** in public release 0.0.12; the development PC's installed candidate has it); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `customer`, `saleType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalInvoice`, `adjustment`, `narration` · operation `busy.sales-returns.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY sales return – create*, called through the Cloud Relay with the organization's cloud token (the same token that reads): a **sales return (credit note)**, the reverse of a sale — the customer is credited, sales and GST debited, the goods come back into `materialCenter`. **Create only**. **SQL Server companies with a SQL login, and Access companies** (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`). Never run it from scripts or a collection run.\n\n**Body** (at most 128 KiB, else `413 REQUEST_TOO_LARGE`; the PC also accepts at most 64 KiB per signed command, so very long lines may be refused `413` before anything is recorded or sent):\n| Field | Required | Rule |\n| --- | --- | --- |\n| `companyCode`, `financialYear` | yes | one company and one four-digit starting year within the token's scope |\n| `returnReference` | yes | your own reference, 1-60 characters (trimmed); unique among the company's sales returns of the year (BUSY's own included) |\n| `date` | yes | `YYYY-MM-DD`, inside the financial year |\n| `customer`, `saleType`, `materialCenter` | yes | `{ \"code\": n }` or `{ \"name\": \"…\" }` |\n| `voucherSeries` | optional | needed when the company has more than one sales-return series |\n| `lines` | yes | 1-100, the sales invoice's line rules with **quantity at most 2 decimals** |\n| `originalInvoice` | optional | `{ \"voucherId\": n }` or `{ \"number\": \"…\" }`: the customer's own, non-cancelled sales invoice of the year, dated on or before the return; no item comes back beyond what it sold less earlier returns |\n| `adjustment` | optional (on account) | `{ \"type\": \"onAccount\" }`, `{ \"type\": \"againstOriginalInvoice\", \"amount\"?: n }` (needs `originalInvoice`; never over-settles its bill) or `{ \"type\": \"newReference\", \"number\": \"…\", \"dueDate\"?: \"…\", \"amount\"?: n }`; only for a customer kept bill by bill |\n| `narration` | optional | 1-94 |\nNo billing block, return number, amount or total; any other member is refused (`400 BAD_REQUEST`).\n\n**Duplicates and unknown outcomes.** A second return with the same `returnReference` is refused `409 SALES_RETURN_REFERENCE_TAKEN` with `details.returnId`; nothing is written. After `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` do not resend blind and never with a new reference: `cloudIdempotencyKey` is kept, so an accidental resend is refused `409`. Look the return up by `returnReference`; to recover deliberately, unset `cloudIdempotencyKey` and resend the **same** body. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back or an adjusted bill differs (`details.returnId`, `details.mismatchedFields`): do not resend.\n\n**Other refusals:** `404 SALES_RETURN_ORIGINAL_NOT_FOUND`; `422 SALES_RETURN_ORIGINAL_MISMATCH` / `_CANCELLED` / `_AMBIGUOUS` / `SALES_RETURN_HISTORY_AMBIGUOUS` / `_DATE_BEFORE_ORIGINAL` / `_SALE_TYPE_MISMATCH` / `_QUANTITY_EXCEEDS_SALE` / `_SALE_TYPE_UNSUPPORTED` / `_TAX_UNSUPPORTED` / `_ITEM_UNSUPPORTED` / `_ADJUSTMENT_UNSUPPORTED` / `_BILL_NOT_FOUND` / `_BILL_OVERSETTLED`; `409 SALES_RETURN_NEW_REFERENCE_TAKEN`, `409 SALES_RETURN_MASTER_CHANGED`; `503 BUSY_COM_QUEUE_TIMEOUT` (the only retryable code).\n\n**Safe test guidance:** development-test company only (`COMP0002` / `2026`); set `returnReference` to a new, unique test reference before each send; to return against an invoice, add `\"originalInvoice\": { \"voucherId\": {{salesInvoiceId}} }` and `\"adjustment\": { \"type\": \"againstOriginalInvoice\" }`. Test returns stay in BUSY. The examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `originalInvoice` is `422 GST_MODE_UNSUPPORTED`.\n- `salesman` (optional): `{ \"code\": n }` or `{ \"name\": \"…\" }`; omitted or `null` keeps BUSY's default. Codes: `409 SALESMAN_CONFIGURATION_UNSUPPORTED`, `409 SALESMAN_CONFIGURATION_CHANGED`.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`). `422 SALES_RETURN_SERIES_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000306"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"WRITE_RESULT_UNKNOWN\",\n      \"message\": \"The PC's answer to this sales return did not reach AI Zeny, so whether BUSY saved it is not known. Look the return up by its returnReference before trying again; a retry with the same returnReference is refused if the first one saved (409 SALES_RETURN_REFERENCE_TAKEN with details.returnId).\",\n      \"details\": { \"reconciliation\": \"notChecked\" }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000306\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"5e426014-a09a-0962-d255-c7149c0df2c4"},{"name":"⚠ BUSY purchase – create (writes to BUSY)","id":"af23d6a4-649b-1448-85b2-867ed63470db","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": { \"number\": \"{{purchaseReference}}\", \"date\": \"2026-10-15\" },\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PUR SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100, \"description\": [\"Postman test purchase\"] }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/purchase-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)\n<strong>Status (2026-10-23):</strong> deployed and live (release <code>790395a</code>). The PC needs an AI Zeny version that relays purchases (Windows <code>0723a72</code> or later — <strong>not</strong> in public release 0.0.12); an earlier version answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>purchaseReference</code>, <code>date</code>, <code>supplierInvoice { number, date }</code>, <code>supplier</code>, <code>purchaseType</code>, <code>materialCenter</code>, <code>lines</code> · <strong>Optional:</strong> <code>voucherNumber</code>, <code>voucherSeries</code>, <code>billSundries</code>, <code>dueDate</code>, <code>narration</code>, and per line <code>discountPercent</code>, <code>mrp</code>, <code>description</code>, <code>parameters</code> · operation <code>busy.purchases.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.</strong> Same operation, body and answer as the Local request <em>Local PC → ⚠ Voucher Create → ⚠ BUSY purchase – create</em>, called through the Cloud Relay with the same organization token that reads. Create only: it never changes, cancels or deletes a purchase. SQL Server companies with a SQL login, and Access companies (Windows <code>6c5776d</code> or later; an earlier PC answers Access with <code>409 MASTER_WRITE_PROVIDER_UNSUPPORTED</code>).</p>\n<p><strong>Three identities (checked on the PC before BUSY):</strong></p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th>Rule</th>\n<th>Refusal</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>purchaseReference</code></td>\n<td>yours, 1-60, unique among the company's purchases of the year</td>\n<td><code>409 PURCHASE_REFERENCE_TAKEN</code> + <code>details.purchaseId</code></td>\n</tr>\n<tr>\n<td><code>supplierInvoice.number</code> (+ <code>date</code> ≤ <code>date</code>)</td>\n<td>the supplier's bill, 1-25, unique per supplier and year (BUSY never checks it)</td>\n<td><code>409 PURCHASE_SUPPLIER_INVOICE_TAKEN</code> + <code>details.purchaseId</code></td>\n</tr>\n<tr>\n<td><code>voucherNumber</code></td>\n<td>1-25, default the supplier invoice number, new in a <strong>manually</strong> numbered series</td>\n<td><code>409 PURCHASE_NUMBER_TAKEN</code>; automatic series <code>422 PURCHASE_SERIES_UNSUPPORTED</code></td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>Body rules (cloud and PC):</strong> lines 1-100; <code>quantity</code> &gt; 0 with <strong>at most 2 decimals</strong> (BUSY keeps a purchase's quantity to 2); <code>rate</code> ≥ 0, 2 decimals; <code>discountPercent</code> 0-100, 2 decimals; the rate less the discount must come to at most 2 decimals (refused, never rounded); <code>mrp</code> ≥ 0; <code>description</code> 1-4 × 1-40; <code>parameters</code> (required for a parameter-wise item, refused for any other): 1-100 rows <code>{ value 1-20, quantity }</code>, each value once per line without case, adding up exactly to the line's quantity — else <code>422 PURCHASE_PARAMETERS_INVALID</code>, decided in the cloud before anything is sent. <code>billSundries</code> (≤ 10): at most one discount <code>{ billSundry, percent }</code> (AI Zeny spreads it over the lines' costs as BUSY's window does), fixed charges <code>{ billSundry, amount }</code>, at most one round-off ≤ 0.99. <code>dueDate</code> on or after <code>date</code>, ≤ 5 years, only for a bill-by-bill supplier (<code>422 PURCHASE_DUE_DATE_UNSUPPORTED</code>). Body ≤ <strong>128 KiB</strong> (<code>413</code>), and the signed command ≤ 64 KiB.</p>\n<p><strong>Idempotency-Key lifecycle (Postman):</strong> minted only when none is held (<code>cloudIdempotencyKey</code>, shared with the other Cloud writes); <strong>kept</strong> after any <code>504</code> or <code>409 REQUEST_IN_PROGRESS</code> / <code>IDEMPOTENT_REPLAY_UNAVAILABLE</code> / <code>IDEMPOTENCY_KEY_REUSED</code>, so an accidental resend is refused, never run; cleared after a definite answer. Never a fresh <code>83db9ae0-3c4c-4a7f-8cd2-562581269095</code> per send.</p>\n<p><strong>Uncertain writes:</strong> <code>504 WRITE_RESULT_UNKNOWN</code> (the PC's answer did not reach AI Zeny; <code>details.reconciliation</code> <code>notChecked</code>) and <code>504 BUSY_WRITE_UNCERTAIN</code> (<code>found</code> + <code>purchaseId</code> / <code>notFound</code> / <code>notChecked</code>) are neither success nor failure. Look the purchase up by <code>purchaseReference</code> first; to recover deliberately unset <code>cloudIdempotencyKey</code> and resend the <strong>same</strong> body (same <code>purchaseReference</code>): if the first send saved, the answer is <code>409 PURCHASE_REFERENCE_TAKEN</code> with <code>details.purchaseId</code>. <code>502 BUSY_WRITE_UNVERIFIED</code> = saved but the read-back differs: check it in BUSY, do not resend. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> is the only retryable write error.</p>\n<p><strong>Other errors:</strong> <code>409 PURCHASE_BILL_REFERENCE_TAKEN</code>, <code>PURCHASE_MASTER_CHANGED</code>; <code>422 MASTER_REFERENCE_NOT_FOUND</code> / <code>_AMBIGUOUS</code> (nothing is created), <code>PURCHASE_SUPPLIER_UNSUPPORTED</code>, <code>PURCHASE_TYPE_UNSUPPORTED</code>, <code>PURCHASE_TAX_UNSUPPORTED</code>, <code>PURCHASE_ITEM_UNSUPPORTED</code>, <code>PURCHASE_BILL_SUNDRY_UNSUPPORTED</code>, <code>BUSY_DATA_INCONSISTENT</code>; <code>502 BUSY_WRITE_FAILED</code>. Full list: operation reference (<code>docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md</code>, Writes to BUSY).</p>\n<p><strong>Safe test guidance:</strong> development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>), a <strong>new, unique</strong> <code>purchaseReference</code> of at most 25 characters (current value) for each purchase — the request is skipped without one. A created test purchase stays in BUSY. Saved examples are synthetic.</p>\n<p><strong>Durable queue:</strong> optional strict <code>queue</code> (omitted or <code>false</code>: synchronous; <code>true</code>: a <code>202</code> job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.</p>\n<hr />\n<p><strong>Parity update (2026-10-23, deployed in release <code>790395a</code>; the PC must be Windows <code>6c5776d</code> or later for these members).</strong> This request's body sends only the basic members. New optional members and codes:</p>\n<ul>\n<li><code>queue</code> (optional, <code>true</code> or <code>false</code>, default <code>false</code>; <code>null</code> is refused <code>400</code>): with <code>true</code> the PC accepts the write on its durable queue and the answer is <strong><code>202</code></strong> with <code>data: null</code> and <code>metadata.queued: true</code>, <code>metadata.jobId</code> (32 hex), <code>metadata.status</code> — acceptance, <strong>not</strong> a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable <code>companyCode</code>/four-digit <code>financialYear</code>; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (<code>202</code>) and fails there. The cloud sends it once.</li>\n<li>GST modes: <code>taxCalculation</code> (<code>auto</code> default, or <code>manual</code>) and <code>pricingMode</code> (<code>gstExclusive</code> default, or <code>gstInclusive</code>, which must match the voucher type's inclusive flag). Manual needs every line's <code>amounts { taxableAmount, cgst, sgst, igst, amount }</code> and the voucher <code>totals</code> (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: <code>422 GST_AMOUNTS_INVALID</code>, <code>422 GST_MODE_UNSUPPORTED</code>, <code>409 GST_CONFIGURATION_CHANGED</code>. A new mode with <code>billSundries</code> or parameter-wise stock is <code>422 GST_MODE_UNSUPPORTED</code>.</li>\n<li>Line <code>description</code>: 1-10 positions of at most 40 characters (<code>null</code> or empty keeps a position empty; at least one holds text); the series must allow that many lines (<code>422 DESCRIPTION_LINE_NOT_ALLOWED</code>).</li>\n<li>Shared refusals of every write, answered before anything is written: <code>403 PLAN_FEATURE_NOT_INCLUDED</code>, <code>409 PLAN_NOT_KNOWN</code>, <code>503 BUSY_COM_RECOVERY_REQUIRED</code>, <code>409 BUSY_WRITE_TARGET_CHANGED</code>, <code>422 BUSY_SETTING_REQUIRED</code>, <code>502 BUSY_SETTINGS_UNREADABLE</code>; queue refusals <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>, <code>503 WRITE_QUEUE_UNAVAILABLE</code>.</li>\n</ul>\n<p>Scenario requests for the new members are in this folder, named <code>⚠ Scenario – …</code> and <code>⚠ EXPECTED REFUSAL …</code>; they are guarded like this one (<code>confirmMutating</code> = <code>yes</code>, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Cloud Relay has not deployed the new numbering schema; these are documentation examples only. Do not Send until Cloud parity is deployed and verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": {\n    \"number\": \"{{purchaseReference}}\",\n    \"date\": \"2026-10-15\"\n  },\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100,\n      \"description\": [\n        \"Postman test purchase\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test purchase\",\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": {\n    \"number\": \"{{purchaseReference}}\",\n    \"date\": \"2026-10-15\"\n  },\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100,\n      \"description\": [\n        \"Postman test purchase\"\n      ]\n    }\n  ],\n  \"narration\": \"Postman test purchase\",\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","urlObject":{"path":["v1","purchase-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"ef0f41fe-465d-aecd-46cd-e5453ced1713","name":"200 – purchase created (discount spread, freight, round-off, parameter rows) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": { \"number\": \"{{purchaseReference}}\", \"date\": \"2026-10-15\" },\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PUR SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100, \"description\": [\"Postman test purchase\"] }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/purchase-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays purchases (Windows `0723a72` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `purchaseReference`, `date`, `supplierInvoice { number, date }`, `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherNumber`, `voucherSeries`, `billSundries`, `dueDate`, `narration`, and per line `discountPercent`, `mrp`, `description`, `parameters` · operation `busy.purchases.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY purchase – create*, called through the Cloud Relay with the same organization token that reads. Create only: it never changes, cancels or deletes a purchase. SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Three identities (checked on the PC before BUSY):**\n| | Rule | Refusal |\n|---|---|---|\n| `purchaseReference` | yours, 1-60, unique among the company's purchases of the year | `409 PURCHASE_REFERENCE_TAKEN` + `details.purchaseId` |\n| `supplierInvoice.number` (+ `date` ≤ `date`) | the supplier's bill, 1-25, unique per supplier and year (BUSY never checks it) | `409 PURCHASE_SUPPLIER_INVOICE_TAKEN` + `details.purchaseId` |\n| `voucherNumber` | 1-25, default the supplier invoice number, new in a **manually** numbered series | `409 PURCHASE_NUMBER_TAKEN`; automatic series `422 PURCHASE_SERIES_UNSUPPORTED` |\n\n**Body rules (cloud and PC):** lines 1-100; `quantity` > 0 with **at most 2 decimals** (BUSY keeps a purchase's quantity to 2); `rate` ≥ 0, 2 decimals; `discountPercent` 0-100, 2 decimals; the rate less the discount must come to at most 2 decimals (refused, never rounded); `mrp` ≥ 0; `description` 1-4 × 1-40; `parameters` (required for a parameter-wise item, refused for any other): 1-100 rows `{ value 1-20, quantity }`, each value once per line without case, adding up exactly to the line's quantity — else `422 PURCHASE_PARAMETERS_INVALID`, decided in the cloud before anything is sent. `billSundries` (≤ 10): at most one discount `{ billSundry, percent }` (AI Zeny spreads it over the lines' costs as BUSY's window does), fixed charges `{ billSundry, amount }`, at most one round-off ≤ 0.99. `dueDate` on or after `date`, ≤ 5 years, only for a bill-by-bill supplier (`422 PURCHASE_DUE_DATE_UNSUPPORTED`). Body ≤ **128 KiB** (`413`), and the signed command ≤ 64 KiB.\n\n**Idempotency-Key lifecycle (Postman):** minted only when none is held (`cloudIdempotencyKey`, shared with the other Cloud writes); **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, so an accidental resend is refused, never run; cleared after a definite answer. Never a fresh `bee90dec-2ba2-4f9e-972f-949f20f5a733` per send.\n\n**Uncertain writes:** `504 WRITE_RESULT_UNKNOWN` (the PC's answer did not reach AI Zeny; `details.reconciliation` `notChecked`) and `504 BUSY_WRITE_UNCERTAIN` (`found` + `purchaseId` / `notFound` / `notChecked`) are neither success nor failure. Look the purchase up by `purchaseReference` first; to recover deliberately unset `cloudIdempotencyKey` and resend the **same** body (same `purchaseReference`): if the first send saved, the answer is `409 PURCHASE_REFERENCE_TAKEN` with `details.purchaseId`. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back differs: check it in BUSY, do not resend. `503 BUSY_COM_QUEUE_TIMEOUT` is the only retryable write error.\n\n**Other errors:** `409 PURCHASE_BILL_REFERENCE_TAKEN`, `PURCHASE_MASTER_CHANGED`; `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS` (nothing is created), `PURCHASE_SUPPLIER_UNSUPPORTED`, `PURCHASE_TYPE_UNSUPPORTED`, `PURCHASE_TAX_UNSUPPORTED`, `PURCHASE_ITEM_UNSUPPORTED`, `PURCHASE_BILL_SUNDRY_UNSUPPORTED`, `BUSY_DATA_INCONSISTENT`; `502 BUSY_WRITE_FAILED`. Full list: operation reference (`docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md`, Writes to BUSY).\n\n**Safe test guidance:** development-test company only (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`), a **new, unique** `purchaseReference` of at most 25 characters (current value) for each purchase — the request is skipped without one. A created test purchase stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `billSundries` or parameter-wise stock is `422 GST_MODE_UNSUPPORTED`.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`).\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000101","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"purchaseId\": 8840,\n    \"voucherNumber\": \"SUP-7781\",\n    \"purchaseReference\": \"WEB-PUR-50112\",\n    \"date\": \"2026-10-15\",\n    \"voucherSeries\": { \"code\": 251, \"name\": \"Main\" },\n    \"supplier\": { \"code\": 7101, \"name\": \"Synthetic Supplies\" },\n    \"purchaseType\": { \"code\": 9312, \"name\": \"Local-ItemWise\" },\n    \"taxation\": \"local\",\n    \"materialCenter\": { \"code\": 9501, \"name\": \"Main Store\" },\n    \"supplierInvoice\": { \"number\": \"SUP-7781\", \"date\": \"2026-10-14\" },\n    \"lines\": [\n      { \"lineNumber\": 1, \"item\": { \"code\": 9401, \"name\": \"Synthetic Item\" }, \"unit\": \"Pcs.\", \"quantity\": 10, \"rate\": 120, \"discountPercent\": 0, \"netRate\": 120, \"taxableAmount\": 1200, \"cgst\": 72, \"sgst\": 72, \"igst\": 0, \"taxAmount\": 144, \"amount\": 1344, \"discountShare\": 26.88, \"cost\": 1173.12, \"mrp\": null, \"description\": [], \"parameters\": [] },\n      { \"lineNumber\": 2, \"item\": { \"code\": 9402, \"name\": \"Synthetic Colour Item\" }, \"unit\": \"Pcs.\", \"quantity\": 5, \"rate\": 80, \"discountPercent\": 0, \"netRate\": 80, \"taxableAmount\": 400, \"cgst\": 24, \"sgst\": 24, \"igst\": 0, \"taxAmount\": 48, \"amount\": 448, \"discountShare\": 8.96, \"cost\": 391.04, \"mrp\": null, \"description\": [], \"parameters\": [ { \"value\": \"RED\", \"quantity\": 3, \"amount\": 240 }, { \"value\": \"BLUE\", \"quantity\": 2, \"amount\": 160 } ] }\n    ],\n    \"billSundries\": [\n      { \"lineNumber\": 1, \"billSundry\": { \"code\": 9601, \"name\": \"Discount\" }, \"kind\": \"discount\", \"percent\": 2, \"baseAmount\": 1792, \"amount\": 35.84, \"effect\": \"subtract\" },\n      { \"lineNumber\": 2, \"billSundry\": { \"code\": 9602, \"name\": \"Freight & Forwarding Charges\" }, \"kind\": \"charge\", \"percent\": null, \"baseAmount\": null, \"amount\": 50, \"effect\": \"add\" },\n      { \"lineNumber\": 3, \"billSundry\": { \"code\": 9604, \"name\": \"Rounded Off (-)\" }, \"kind\": \"roundOff\", \"percent\": null, \"baseAmount\": null, \"amount\": 0.16, \"effect\": \"subtract\" }\n    ],\n    \"totals\": { \"quantity\": 15, \"taxableAmount\": 1600, \"cgst\": 96, \"sgst\": 96, \"igst\": 0, \"taxAmount\": 192, \"discount\": 35.84, \"charges\": 50, \"roundOff\": -0.16, \"purchaseValue\": 1564.16, \"amount\": 1806 },\n    \"billReference\": { \"number\": \"SUP-7781\", \"amount\": 1806, \"dueDate\": \"2026-11-14\" },\n    \"narration\": \"Synthetic purchase from the supplier portal\",\n    \"ledger\": [\n      { \"account\": { \"code\": 7101, \"name\": \"Synthetic Supplies\" }, \"debit\": 0, \"credit\": 1806 },\n      { \"account\": { \"code\": 9201, \"name\": \"Synthetic Purchase\" }, \"debit\": 1564.16, \"credit\": 0 },\n      { \"account\": { \"code\": 9221, \"name\": \"Synthetic Freight\" }, \"debit\": 50, \"credit\": 0 },\n      { \"account\": { \"code\": 9231, \"name\": \"Synthetic Round Off\" }, \"debit\": 0, \"credit\": 0.16 },\n      { \"account\": { \"code\": 9213, \"name\": \"Synthetic CGST Input\" }, \"debit\": 96, \"credit\": 0 },\n      { \"account\": { \"code\": 9214, \"name\": \"Synthetic SGST Input\" }, \"debit\": 96, \"credit\": 0 }\n    ]\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.purchases.create\",\n    \"requestId\": \"rq_0SYNTHET1C0000000000000101\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 2,\n    \"verification\": [\"busyReadBack\", \"savedRows\"],\n    \"elapsedMs\": 2930,\n    \"executedAt\": \"2026-10-15T10:00:00+00:00\"\n  }\n}"},{"id":"48f97880-6694-ddab-63ec-31fa0ec040a4","name":"409 – PURCHASE_REFERENCE_TAKEN: a resend after a saved purchase (details.purchaseId; nothing written) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": { \"number\": \"{{purchaseReference}}\", \"date\": \"2026-10-15\" },\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PUR SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100, \"description\": [\"Postman test purchase\"] }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/purchase-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays purchases (Windows `0723a72` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `purchaseReference`, `date`, `supplierInvoice { number, date }`, `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherNumber`, `voucherSeries`, `billSundries`, `dueDate`, `narration`, and per line `discountPercent`, `mrp`, `description`, `parameters` · operation `busy.purchases.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY purchase – create*, called through the Cloud Relay with the same organization token that reads. Create only: it never changes, cancels or deletes a purchase. SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Three identities (checked on the PC before BUSY):**\n| | Rule | Refusal |\n|---|---|---|\n| `purchaseReference` | yours, 1-60, unique among the company's purchases of the year | `409 PURCHASE_REFERENCE_TAKEN` + `details.purchaseId` |\n| `supplierInvoice.number` (+ `date` ≤ `date`) | the supplier's bill, 1-25, unique per supplier and year (BUSY never checks it) | `409 PURCHASE_SUPPLIER_INVOICE_TAKEN` + `details.purchaseId` |\n| `voucherNumber` | 1-25, default the supplier invoice number, new in a **manually** numbered series | `409 PURCHASE_NUMBER_TAKEN`; automatic series `422 PURCHASE_SERIES_UNSUPPORTED` |\n\n**Body rules (cloud and PC):** lines 1-100; `quantity` > 0 with **at most 2 decimals** (BUSY keeps a purchase's quantity to 2); `rate` ≥ 0, 2 decimals; `discountPercent` 0-100, 2 decimals; the rate less the discount must come to at most 2 decimals (refused, never rounded); `mrp` ≥ 0; `description` 1-4 × 1-40; `parameters` (required for a parameter-wise item, refused for any other): 1-100 rows `{ value 1-20, quantity }`, each value once per line without case, adding up exactly to the line's quantity — else `422 PURCHASE_PARAMETERS_INVALID`, decided in the cloud before anything is sent. `billSundries` (≤ 10): at most one discount `{ billSundry, percent }` (AI Zeny spreads it over the lines' costs as BUSY's window does), fixed charges `{ billSundry, amount }`, at most one round-off ≤ 0.99. `dueDate` on or after `date`, ≤ 5 years, only for a bill-by-bill supplier (`422 PURCHASE_DUE_DATE_UNSUPPORTED`). Body ≤ **128 KiB** (`413`), and the signed command ≤ 64 KiB.\n\n**Idempotency-Key lifecycle (Postman):** minted only when none is held (`cloudIdempotencyKey`, shared with the other Cloud writes); **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, so an accidental resend is refused, never run; cleared after a definite answer. Never a fresh `1d85323f-1148-46d5-bb02-7b11e4040a6a` per send.\n\n**Uncertain writes:** `504 WRITE_RESULT_UNKNOWN` (the PC's answer did not reach AI Zeny; `details.reconciliation` `notChecked`) and `504 BUSY_WRITE_UNCERTAIN` (`found` + `purchaseId` / `notFound` / `notChecked`) are neither success nor failure. Look the purchase up by `purchaseReference` first; to recover deliberately unset `cloudIdempotencyKey` and resend the **same** body (same `purchaseReference`): if the first send saved, the answer is `409 PURCHASE_REFERENCE_TAKEN` with `details.purchaseId`. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back differs: check it in BUSY, do not resend. `503 BUSY_COM_QUEUE_TIMEOUT` is the only retryable write error.\n\n**Other errors:** `409 PURCHASE_BILL_REFERENCE_TAKEN`, `PURCHASE_MASTER_CHANGED`; `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS` (nothing is created), `PURCHASE_SUPPLIER_UNSUPPORTED`, `PURCHASE_TYPE_UNSUPPORTED`, `PURCHASE_TAX_UNSUPPORTED`, `PURCHASE_ITEM_UNSUPPORTED`, `PURCHASE_BILL_SUNDRY_UNSUPPORTED`, `BUSY_DATA_INCONSISTENT`; `502 BUSY_WRITE_FAILED`. Full list: operation reference (`docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md`, Writes to BUSY).\n\n**Safe test guidance:** development-test company only (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`), a **new, unique** `purchaseReference` of at most 25 characters (current value) for each purchase — the request is skipped without one. A created test purchase stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `billSundries` or parameter-wise stock is `422 GST_MODE_UNSUPPORTED`.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`).\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000102","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PURCHASE_REFERENCE_TAKEN\",\n      \"message\": \"A purchase of this company and financial year already holds this purchaseReference. A create never changes an existing purchase; if your earlier call saved it, metadata.error.details.purchaseId names it.\",\n      \"field\": \"purchaseReference\",\n      \"details\": { \"purchaseId\": 8840 }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000102\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"9fc0bbe6-f7cb-9a90-9b78-5f7c678a3d0f","name":"409 – PURCHASE_SUPPLIER_INVOICE_TAKEN: the supplier's bill is already entered (details.purchaseId) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": { \"number\": \"{{purchaseReference}}\", \"date\": \"2026-10-15\" },\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PUR SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100, \"description\": [\"Postman test purchase\"] }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/purchase-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays purchases (Windows `0723a72` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `purchaseReference`, `date`, `supplierInvoice { number, date }`, `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherNumber`, `voucherSeries`, `billSundries`, `dueDate`, `narration`, and per line `discountPercent`, `mrp`, `description`, `parameters` · operation `busy.purchases.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY purchase – create*, called through the Cloud Relay with the same organization token that reads. Create only: it never changes, cancels or deletes a purchase. SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Three identities (checked on the PC before BUSY):**\n| | Rule | Refusal |\n|---|---|---|\n| `purchaseReference` | yours, 1-60, unique among the company's purchases of the year | `409 PURCHASE_REFERENCE_TAKEN` + `details.purchaseId` |\n| `supplierInvoice.number` (+ `date` ≤ `date`) | the supplier's bill, 1-25, unique per supplier and year (BUSY never checks it) | `409 PURCHASE_SUPPLIER_INVOICE_TAKEN` + `details.purchaseId` |\n| `voucherNumber` | 1-25, default the supplier invoice number, new in a **manually** numbered series | `409 PURCHASE_NUMBER_TAKEN`; automatic series `422 PURCHASE_SERIES_UNSUPPORTED` |\n\n**Body rules (cloud and PC):** lines 1-100; `quantity` > 0 with **at most 2 decimals** (BUSY keeps a purchase's quantity to 2); `rate` ≥ 0, 2 decimals; `discountPercent` 0-100, 2 decimals; the rate less the discount must come to at most 2 decimals (refused, never rounded); `mrp` ≥ 0; `description` 1-4 × 1-40; `parameters` (required for a parameter-wise item, refused for any other): 1-100 rows `{ value 1-20, quantity }`, each value once per line without case, adding up exactly to the line's quantity — else `422 PURCHASE_PARAMETERS_INVALID`, decided in the cloud before anything is sent. `billSundries` (≤ 10): at most one discount `{ billSundry, percent }` (AI Zeny spreads it over the lines' costs as BUSY's window does), fixed charges `{ billSundry, amount }`, at most one round-off ≤ 0.99. `dueDate` on or after `date`, ≤ 5 years, only for a bill-by-bill supplier (`422 PURCHASE_DUE_DATE_UNSUPPORTED`). Body ≤ **128 KiB** (`413`), and the signed command ≤ 64 KiB.\n\n**Idempotency-Key lifecycle (Postman):** minted only when none is held (`cloudIdempotencyKey`, shared with the other Cloud writes); **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, so an accidental resend is refused, never run; cleared after a definite answer. Never a fresh `3ecbe6f8-d68a-47e9-bacd-9492b6da15ca` per send.\n\n**Uncertain writes:** `504 WRITE_RESULT_UNKNOWN` (the PC's answer did not reach AI Zeny; `details.reconciliation` `notChecked`) and `504 BUSY_WRITE_UNCERTAIN` (`found` + `purchaseId` / `notFound` / `notChecked`) are neither success nor failure. Look the purchase up by `purchaseReference` first; to recover deliberately unset `cloudIdempotencyKey` and resend the **same** body (same `purchaseReference`): if the first send saved, the answer is `409 PURCHASE_REFERENCE_TAKEN` with `details.purchaseId`. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back differs: check it in BUSY, do not resend. `503 BUSY_COM_QUEUE_TIMEOUT` is the only retryable write error.\n\n**Other errors:** `409 PURCHASE_BILL_REFERENCE_TAKEN`, `PURCHASE_MASTER_CHANGED`; `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS` (nothing is created), `PURCHASE_SUPPLIER_UNSUPPORTED`, `PURCHASE_TYPE_UNSUPPORTED`, `PURCHASE_TAX_UNSUPPORTED`, `PURCHASE_ITEM_UNSUPPORTED`, `PURCHASE_BILL_SUNDRY_UNSUPPORTED`, `BUSY_DATA_INCONSISTENT`; `502 BUSY_WRITE_FAILED`. Full list: operation reference (`docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md`, Writes to BUSY).\n\n**Safe test guidance:** development-test company only (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`), a **new, unique** `purchaseReference` of at most 25 characters (current value) for each purchase — the request is skipped without one. A created test purchase stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `billSundries` or parameter-wise stock is `422 GST_MODE_UNSUPPORTED`.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`).\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000103","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PURCHASE_SUPPLIER_INVOICE_TAKEN\",\n      \"message\": \"A purchase from this supplier in this financial year already records this supplier invoice number (metadata.error.details.purchaseId). The same bill is not entered twice; check it in BUSY.\",\n      \"field\": \"supplierInvoice.number\",\n      \"details\": { \"purchaseId\": 8840 }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000103\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"8743145e-3a5c-371a-4c03-d42359a8834e","name":"400 – a quantity with 3 decimals, refused by the cloud before anything is sent [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": { \"number\": \"{{purchaseReference}}\", \"date\": \"2026-10-15\" },\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PUR SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100, \"description\": [\"Postman test purchase\"] }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/purchase-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays purchases (Windows `0723a72` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `purchaseReference`, `date`, `supplierInvoice { number, date }`, `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherNumber`, `voucherSeries`, `billSundries`, `dueDate`, `narration`, and per line `discountPercent`, `mrp`, `description`, `parameters` · operation `busy.purchases.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY purchase – create*, called through the Cloud Relay with the same organization token that reads. Create only: it never changes, cancels or deletes a purchase. SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Three identities (checked on the PC before BUSY):**\n| | Rule | Refusal |\n|---|---|---|\n| `purchaseReference` | yours, 1-60, unique among the company's purchases of the year | `409 PURCHASE_REFERENCE_TAKEN` + `details.purchaseId` |\n| `supplierInvoice.number` (+ `date` ≤ `date`) | the supplier's bill, 1-25, unique per supplier and year (BUSY never checks it) | `409 PURCHASE_SUPPLIER_INVOICE_TAKEN` + `details.purchaseId` |\n| `voucherNumber` | 1-25, default the supplier invoice number, new in a **manually** numbered series | `409 PURCHASE_NUMBER_TAKEN`; automatic series `422 PURCHASE_SERIES_UNSUPPORTED` |\n\n**Body rules (cloud and PC):** lines 1-100; `quantity` > 0 with **at most 2 decimals** (BUSY keeps a purchase's quantity to 2); `rate` ≥ 0, 2 decimals; `discountPercent` 0-100, 2 decimals; the rate less the discount must come to at most 2 decimals (refused, never rounded); `mrp` ≥ 0; `description` 1-4 × 1-40; `parameters` (required for a parameter-wise item, refused for any other): 1-100 rows `{ value 1-20, quantity }`, each value once per line without case, adding up exactly to the line's quantity — else `422 PURCHASE_PARAMETERS_INVALID`, decided in the cloud before anything is sent. `billSundries` (≤ 10): at most one discount `{ billSundry, percent }` (AI Zeny spreads it over the lines' costs as BUSY's window does), fixed charges `{ billSundry, amount }`, at most one round-off ≤ 0.99. `dueDate` on or after `date`, ≤ 5 years, only for a bill-by-bill supplier (`422 PURCHASE_DUE_DATE_UNSUPPORTED`). Body ≤ **128 KiB** (`413`), and the signed command ≤ 64 KiB.\n\n**Idempotency-Key lifecycle (Postman):** minted only when none is held (`cloudIdempotencyKey`, shared with the other Cloud writes); **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, so an accidental resend is refused, never run; cleared after a definite answer. Never a fresh `eb2be5b3-f204-4891-8513-4d505466609e` per send.\n\n**Uncertain writes:** `504 WRITE_RESULT_UNKNOWN` (the PC's answer did not reach AI Zeny; `details.reconciliation` `notChecked`) and `504 BUSY_WRITE_UNCERTAIN` (`found` + `purchaseId` / `notFound` / `notChecked`) are neither success nor failure. Look the purchase up by `purchaseReference` first; to recover deliberately unset `cloudIdempotencyKey` and resend the **same** body (same `purchaseReference`): if the first send saved, the answer is `409 PURCHASE_REFERENCE_TAKEN` with `details.purchaseId`. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back differs: check it in BUSY, do not resend. `503 BUSY_COM_QUEUE_TIMEOUT` is the only retryable write error.\n\n**Other errors:** `409 PURCHASE_BILL_REFERENCE_TAKEN`, `PURCHASE_MASTER_CHANGED`; `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS` (nothing is created), `PURCHASE_SUPPLIER_UNSUPPORTED`, `PURCHASE_TYPE_UNSUPPORTED`, `PURCHASE_TAX_UNSUPPORTED`, `PURCHASE_ITEM_UNSUPPORTED`, `PURCHASE_BILL_SUNDRY_UNSUPPORTED`, `BUSY_DATA_INCONSISTENT`; `502 BUSY_WRITE_FAILED`. Full list: operation reference (`docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md`, Writes to BUSY).\n\n**Safe test guidance:** development-test company only (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`), a **new, unique** `purchaseReference` of at most 25 characters (current value) for each purchase — the request is skipped without one. A created test purchase stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `billSundries` or parameter-wise stock is `422 GST_MODE_UNSUPPORTED`.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`).\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"lines[0].quantity must have at most 2 decimals: BUSY keeps a purchase's quantity to 2 decimals.\",\n      \"field\": \"lines[0].quantity\"\n    },\n    \"requestId\": \"00000000-5e5e-4000-8000-000000000101\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"fef7b030-57a6-d663-cfd9-62c159e6c008","name":"422 – PURCHASE_PARAMETERS_INVALID: parameter rows do not add up (decided by the cloud, nothing sent) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": { \"number\": \"{{purchaseReference}}\", \"date\": \"2026-10-15\" },\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PUR SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100, \"description\": [\"Postman test purchase\"] }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/purchase-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays purchases (Windows `0723a72` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `purchaseReference`, `date`, `supplierInvoice { number, date }`, `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherNumber`, `voucherSeries`, `billSundries`, `dueDate`, `narration`, and per line `discountPercent`, `mrp`, `description`, `parameters` · operation `busy.purchases.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY purchase – create*, called through the Cloud Relay with the same organization token that reads. Create only: it never changes, cancels or deletes a purchase. SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Three identities (checked on the PC before BUSY):**\n| | Rule | Refusal |\n|---|---|---|\n| `purchaseReference` | yours, 1-60, unique among the company's purchases of the year | `409 PURCHASE_REFERENCE_TAKEN` + `details.purchaseId` |\n| `supplierInvoice.number` (+ `date` ≤ `date`) | the supplier's bill, 1-25, unique per supplier and year (BUSY never checks it) | `409 PURCHASE_SUPPLIER_INVOICE_TAKEN` + `details.purchaseId` |\n| `voucherNumber` | 1-25, default the supplier invoice number, new in a **manually** numbered series | `409 PURCHASE_NUMBER_TAKEN`; automatic series `422 PURCHASE_SERIES_UNSUPPORTED` |\n\n**Body rules (cloud and PC):** lines 1-100; `quantity` > 0 with **at most 2 decimals** (BUSY keeps a purchase's quantity to 2); `rate` ≥ 0, 2 decimals; `discountPercent` 0-100, 2 decimals; the rate less the discount must come to at most 2 decimals (refused, never rounded); `mrp` ≥ 0; `description` 1-4 × 1-40; `parameters` (required for a parameter-wise item, refused for any other): 1-100 rows `{ value 1-20, quantity }`, each value once per line without case, adding up exactly to the line's quantity — else `422 PURCHASE_PARAMETERS_INVALID`, decided in the cloud before anything is sent. `billSundries` (≤ 10): at most one discount `{ billSundry, percent }` (AI Zeny spreads it over the lines' costs as BUSY's window does), fixed charges `{ billSundry, amount }`, at most one round-off ≤ 0.99. `dueDate` on or after `date`, ≤ 5 years, only for a bill-by-bill supplier (`422 PURCHASE_DUE_DATE_UNSUPPORTED`). Body ≤ **128 KiB** (`413`), and the signed command ≤ 64 KiB.\n\n**Idempotency-Key lifecycle (Postman):** minted only when none is held (`cloudIdempotencyKey`, shared with the other Cloud writes); **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, so an accidental resend is refused, never run; cleared after a definite answer. Never a fresh `bbc5fe31-484a-42fb-9901-f72db859f4ba` per send.\n\n**Uncertain writes:** `504 WRITE_RESULT_UNKNOWN` (the PC's answer did not reach AI Zeny; `details.reconciliation` `notChecked`) and `504 BUSY_WRITE_UNCERTAIN` (`found` + `purchaseId` / `notFound` / `notChecked`) are neither success nor failure. Look the purchase up by `purchaseReference` first; to recover deliberately unset `cloudIdempotencyKey` and resend the **same** body (same `purchaseReference`): if the first send saved, the answer is `409 PURCHASE_REFERENCE_TAKEN` with `details.purchaseId`. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back differs: check it in BUSY, do not resend. `503 BUSY_COM_QUEUE_TIMEOUT` is the only retryable write error.\n\n**Other errors:** `409 PURCHASE_BILL_REFERENCE_TAKEN`, `PURCHASE_MASTER_CHANGED`; `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS` (nothing is created), `PURCHASE_SUPPLIER_UNSUPPORTED`, `PURCHASE_TYPE_UNSUPPORTED`, `PURCHASE_TAX_UNSUPPORTED`, `PURCHASE_ITEM_UNSUPPORTED`, `PURCHASE_BILL_SUNDRY_UNSUPPORTED`, `BUSY_DATA_INCONSISTENT`; `502 BUSY_WRITE_FAILED`. Full list: operation reference (`docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md`, Writes to BUSY).\n\n**Safe test guidance:** development-test company only (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`), a **new, unique** `purchaseReference` of at most 25 characters (current value) for each purchase — the request is skipped without one. A created test purchase stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `billSundries` or parameter-wise stock is `422 GST_MODE_UNSUPPORTED`.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`).\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PURCHASE_PARAMETERS_INVALID\",\n      \"message\": \"The parameter rows' quantities must add up exactly to the line's quantity.\",\n      \"field\": \"lines[1].parameters\"\n    },\n    \"requestId\": \"00000000-5e5e-4000-8000-000000000102\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"ded01234-a8dd-49f1-0379-d8adced0946e","name":"504 – WRITE_RESULT_UNKNOWN: the PC's answer was lost (key kept; look up by purchaseReference) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": { \"number\": \"{{purchaseReference}}\", \"date\": \"2026-10-15\" },\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PUR SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100, \"description\": [\"Postman test purchase\"] }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/purchase-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays purchases (Windows `0723a72` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `purchaseReference`, `date`, `supplierInvoice { number, date }`, `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherNumber`, `voucherSeries`, `billSundries`, `dueDate`, `narration`, and per line `discountPercent`, `mrp`, `description`, `parameters` · operation `busy.purchases.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY purchase – create*, called through the Cloud Relay with the same organization token that reads. Create only: it never changes, cancels or deletes a purchase. SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Three identities (checked on the PC before BUSY):**\n| | Rule | Refusal |\n|---|---|---|\n| `purchaseReference` | yours, 1-60, unique among the company's purchases of the year | `409 PURCHASE_REFERENCE_TAKEN` + `details.purchaseId` |\n| `supplierInvoice.number` (+ `date` ≤ `date`) | the supplier's bill, 1-25, unique per supplier and year (BUSY never checks it) | `409 PURCHASE_SUPPLIER_INVOICE_TAKEN` + `details.purchaseId` |\n| `voucherNumber` | 1-25, default the supplier invoice number, new in a **manually** numbered series | `409 PURCHASE_NUMBER_TAKEN`; automatic series `422 PURCHASE_SERIES_UNSUPPORTED` |\n\n**Body rules (cloud and PC):** lines 1-100; `quantity` > 0 with **at most 2 decimals** (BUSY keeps a purchase's quantity to 2); `rate` ≥ 0, 2 decimals; `discountPercent` 0-100, 2 decimals; the rate less the discount must come to at most 2 decimals (refused, never rounded); `mrp` ≥ 0; `description` 1-4 × 1-40; `parameters` (required for a parameter-wise item, refused for any other): 1-100 rows `{ value 1-20, quantity }`, each value once per line without case, adding up exactly to the line's quantity — else `422 PURCHASE_PARAMETERS_INVALID`, decided in the cloud before anything is sent. `billSundries` (≤ 10): at most one discount `{ billSundry, percent }` (AI Zeny spreads it over the lines' costs as BUSY's window does), fixed charges `{ billSundry, amount }`, at most one round-off ≤ 0.99. `dueDate` on or after `date`, ≤ 5 years, only for a bill-by-bill supplier (`422 PURCHASE_DUE_DATE_UNSUPPORTED`). Body ≤ **128 KiB** (`413`), and the signed command ≤ 64 KiB.\n\n**Idempotency-Key lifecycle (Postman):** minted only when none is held (`cloudIdempotencyKey`, shared with the other Cloud writes); **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, so an accidental resend is refused, never run; cleared after a definite answer. Never a fresh `ad2c5d02-38f5-4b28-aa76-8621b0907f70` per send.\n\n**Uncertain writes:** `504 WRITE_RESULT_UNKNOWN` (the PC's answer did not reach AI Zeny; `details.reconciliation` `notChecked`) and `504 BUSY_WRITE_UNCERTAIN` (`found` + `purchaseId` / `notFound` / `notChecked`) are neither success nor failure. Look the purchase up by `purchaseReference` first; to recover deliberately unset `cloudIdempotencyKey` and resend the **same** body (same `purchaseReference`): if the first send saved, the answer is `409 PURCHASE_REFERENCE_TAKEN` with `details.purchaseId`. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back differs: check it in BUSY, do not resend. `503 BUSY_COM_QUEUE_TIMEOUT` is the only retryable write error.\n\n**Other errors:** `409 PURCHASE_BILL_REFERENCE_TAKEN`, `PURCHASE_MASTER_CHANGED`; `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS` (nothing is created), `PURCHASE_SUPPLIER_UNSUPPORTED`, `PURCHASE_TYPE_UNSUPPORTED`, `PURCHASE_TAX_UNSUPPORTED`, `PURCHASE_ITEM_UNSUPPORTED`, `PURCHASE_BILL_SUNDRY_UNSUPPORTED`, `BUSY_DATA_INCONSISTENT`; `502 BUSY_WRITE_FAILED`. Full list: operation reference (`docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md`, Writes to BUSY).\n\n**Safe test guidance:** development-test company only (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`), a **new, unique** `purchaseReference` of at most 25 characters (current value) for each purchase — the request is skipped without one. A created test purchase stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `billSundries` or parameter-wise stock is `422 GST_MODE_UNSUPPORTED`.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`).\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000113","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"WRITE_RESULT_UNKNOWN\",\n      \"message\": \"The PC's answer to this purchase did not reach AI Zeny, so whether BUSY saved it is not known. Look the purchase up by its purchaseReference before trying again; a retry with the same purchaseReference is refused if the first one saved (409 PURCHASE_REFERENCE_TAKEN with details.purchaseId).\",\n      \"details\": { \"reconciliation\": \"notChecked\" }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000113\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"5bcd55b5-5db7-fddc-5ed5-60e917f2b438","name":"504 – BUSY_WRITE_UNCERTAIN, reconciled found (details.purchaseId; never resend) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": { \"number\": \"{{purchaseReference}}\", \"date\": \"2026-10-15\" },\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PUR SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100, \"description\": [\"Postman test purchase\"] }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/purchase-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays purchases (Windows `0723a72` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `purchaseReference`, `date`, `supplierInvoice { number, date }`, `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherNumber`, `voucherSeries`, `billSundries`, `dueDate`, `narration`, and per line `discountPercent`, `mrp`, `description`, `parameters` · operation `busy.purchases.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY purchase – create*, called through the Cloud Relay with the same organization token that reads. Create only: it never changes, cancels or deletes a purchase. SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Three identities (checked on the PC before BUSY):**\n| | Rule | Refusal |\n|---|---|---|\n| `purchaseReference` | yours, 1-60, unique among the company's purchases of the year | `409 PURCHASE_REFERENCE_TAKEN` + `details.purchaseId` |\n| `supplierInvoice.number` (+ `date` ≤ `date`) | the supplier's bill, 1-25, unique per supplier and year (BUSY never checks it) | `409 PURCHASE_SUPPLIER_INVOICE_TAKEN` + `details.purchaseId` |\n| `voucherNumber` | 1-25, default the supplier invoice number, new in a **manually** numbered series | `409 PURCHASE_NUMBER_TAKEN`; automatic series `422 PURCHASE_SERIES_UNSUPPORTED` |\n\n**Body rules (cloud and PC):** lines 1-100; `quantity` > 0 with **at most 2 decimals** (BUSY keeps a purchase's quantity to 2); `rate` ≥ 0, 2 decimals; `discountPercent` 0-100, 2 decimals; the rate less the discount must come to at most 2 decimals (refused, never rounded); `mrp` ≥ 0; `description` 1-4 × 1-40; `parameters` (required for a parameter-wise item, refused for any other): 1-100 rows `{ value 1-20, quantity }`, each value once per line without case, adding up exactly to the line's quantity — else `422 PURCHASE_PARAMETERS_INVALID`, decided in the cloud before anything is sent. `billSundries` (≤ 10): at most one discount `{ billSundry, percent }` (AI Zeny spreads it over the lines' costs as BUSY's window does), fixed charges `{ billSundry, amount }`, at most one round-off ≤ 0.99. `dueDate` on or after `date`, ≤ 5 years, only for a bill-by-bill supplier (`422 PURCHASE_DUE_DATE_UNSUPPORTED`). Body ≤ **128 KiB** (`413`), and the signed command ≤ 64 KiB.\n\n**Idempotency-Key lifecycle (Postman):** minted only when none is held (`cloudIdempotencyKey`, shared with the other Cloud writes); **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, so an accidental resend is refused, never run; cleared after a definite answer. Never a fresh `17328f61-6ae9-4336-b460-81649227cbb5` per send.\n\n**Uncertain writes:** `504 WRITE_RESULT_UNKNOWN` (the PC's answer did not reach AI Zeny; `details.reconciliation` `notChecked`) and `504 BUSY_WRITE_UNCERTAIN` (`found` + `purchaseId` / `notFound` / `notChecked`) are neither success nor failure. Look the purchase up by `purchaseReference` first; to recover deliberately unset `cloudIdempotencyKey` and resend the **same** body (same `purchaseReference`): if the first send saved, the answer is `409 PURCHASE_REFERENCE_TAKEN` with `details.purchaseId`. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back differs: check it in BUSY, do not resend. `503 BUSY_COM_QUEUE_TIMEOUT` is the only retryable write error.\n\n**Other errors:** `409 PURCHASE_BILL_REFERENCE_TAKEN`, `PURCHASE_MASTER_CHANGED`; `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS` (nothing is created), `PURCHASE_SUPPLIER_UNSUPPORTED`, `PURCHASE_TYPE_UNSUPPORTED`, `PURCHASE_TAX_UNSUPPORTED`, `PURCHASE_ITEM_UNSUPPORTED`, `PURCHASE_BILL_SUNDRY_UNSUPPORTED`, `BUSY_DATA_INCONSISTENT`; `502 BUSY_WRITE_FAILED`. Full list: operation reference (`docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md`, Writes to BUSY).\n\n**Safe test guidance:** development-test company only (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`), a **new, unique** `purchaseReference` of at most 25 characters (current value) for each purchase — the request is skipped without one. A created test purchase stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `billSundries` or parameter-wise stock is `422 GST_MODE_UNSUPPORTED`.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`).\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000104","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"BUSY stopped while saving the purchase; a purchase with this purchaseReference exists now (metadata.error.details.purchaseId). Check it in BUSY; do not send it again.\",\n      \"details\": { \"purchaseId\": 8841, \"reconciliation\": \"found\" }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000104\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"b3a3dd94-acbc-6877-25f7-67d78ede3892","name":"409 – IDEMPOTENT_REPLAY_UNAVAILABLE: an accidental resend with the kept key (not run again) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-15\",\n  \"supplierInvoice\": { \"number\": \"{{purchaseReference}}\", \"date\": \"2026-10-15\" },\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PUR SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100, \"description\": [\"Postman test purchase\"] }\n  ],\n  \"narration\": \"Postman test purchase\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/purchase-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays purchases (Windows `0723a72` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `purchaseReference`, `date`, `supplierInvoice { number, date }`, `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherNumber`, `voucherSeries`, `billSundries`, `dueDate`, `narration`, and per line `discountPercent`, `mrp`, `description`, `parameters` · operation `busy.purchases.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY purchase – create*, called through the Cloud Relay with the same organization token that reads. Create only: it never changes, cancels or deletes a purchase. SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Three identities (checked on the PC before BUSY):**\n| | Rule | Refusal |\n|---|---|---|\n| `purchaseReference` | yours, 1-60, unique among the company's purchases of the year | `409 PURCHASE_REFERENCE_TAKEN` + `details.purchaseId` |\n| `supplierInvoice.number` (+ `date` ≤ `date`) | the supplier's bill, 1-25, unique per supplier and year (BUSY never checks it) | `409 PURCHASE_SUPPLIER_INVOICE_TAKEN` + `details.purchaseId` |\n| `voucherNumber` | 1-25, default the supplier invoice number, new in a **manually** numbered series | `409 PURCHASE_NUMBER_TAKEN`; automatic series `422 PURCHASE_SERIES_UNSUPPORTED` |\n\n**Body rules (cloud and PC):** lines 1-100; `quantity` > 0 with **at most 2 decimals** (BUSY keeps a purchase's quantity to 2); `rate` ≥ 0, 2 decimals; `discountPercent` 0-100, 2 decimals; the rate less the discount must come to at most 2 decimals (refused, never rounded); `mrp` ≥ 0; `description` 1-4 × 1-40; `parameters` (required for a parameter-wise item, refused for any other): 1-100 rows `{ value 1-20, quantity }`, each value once per line without case, adding up exactly to the line's quantity — else `422 PURCHASE_PARAMETERS_INVALID`, decided in the cloud before anything is sent. `billSundries` (≤ 10): at most one discount `{ billSundry, percent }` (AI Zeny spreads it over the lines' costs as BUSY's window does), fixed charges `{ billSundry, amount }`, at most one round-off ≤ 0.99. `dueDate` on or after `date`, ≤ 5 years, only for a bill-by-bill supplier (`422 PURCHASE_DUE_DATE_UNSUPPORTED`). Body ≤ **128 KiB** (`413`), and the signed command ≤ 64 KiB.\n\n**Idempotency-Key lifecycle (Postman):** minted only when none is held (`cloudIdempotencyKey`, shared with the other Cloud writes); **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, so an accidental resend is refused, never run; cleared after a definite answer. Never a fresh `fb537f30-0e35-4779-887d-725e0644a751` per send.\n\n**Uncertain writes:** `504 WRITE_RESULT_UNKNOWN` (the PC's answer did not reach AI Zeny; `details.reconciliation` `notChecked`) and `504 BUSY_WRITE_UNCERTAIN` (`found` + `purchaseId` / `notFound` / `notChecked`) are neither success nor failure. Look the purchase up by `purchaseReference` first; to recover deliberately unset `cloudIdempotencyKey` and resend the **same** body (same `purchaseReference`): if the first send saved, the answer is `409 PURCHASE_REFERENCE_TAKEN` with `details.purchaseId`. `502 BUSY_WRITE_UNVERIFIED` = saved but the read-back differs: check it in BUSY, do not resend. `503 BUSY_COM_QUEUE_TIMEOUT` is the only retryable write error.\n\n**Other errors:** `409 PURCHASE_BILL_REFERENCE_TAKEN`, `PURCHASE_MASTER_CHANGED`; `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS` (nothing is created), `PURCHASE_SUPPLIER_UNSUPPORTED`, `PURCHASE_TYPE_UNSUPPORTED`, `PURCHASE_TAX_UNSUPPORTED`, `PURCHASE_ITEM_UNSUPPORTED`, `PURCHASE_BILL_SUNDRY_UNSUPPORTED`, `BUSY_DATA_INCONSISTENT`; `502 BUSY_WRITE_FAILED`. Full list: operation reference (`docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md`, Writes to BUSY).\n\n**Safe test guidance:** development-test company only (`targetCompanyCode` = `COMP0002`, `financialYear` = `2026`), a **new, unique** `purchaseReference` of at most 25 characters (current value) for each purchase — the request is skipped without one. A created test purchase stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `billSundries` or parameter-wise stock is `422 GST_MODE_UNSUPPORTED`.\n- Line `description`: 1-10 positions of at most 40 characters (`null` or empty keeps a position empty; at least one holds text); the series must allow that many lines (`422 DESCRIPTION_LINE_NOT_ALLOWED`).\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"IDEMPOTENT_REPLAY_UNAVAILABLE\",\n      \"message\": \"That request already finished. Results are never stored, so it cannot be replayed.\",\n      \"details\": { \"requestId\": \"rq_0SYNTHET1C0000000000000113\", \"status\": \"timeout\" }\n    },\n    \"requestId\": \"00000000-5e5e-4000-8000-000000000103\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"af23d6a4-649b-1448-85b2-867ed63470db"},{"name":"⚠ BUSY purchase return – create (writes to BUSY)","id":"c6d4df11-4b9d-d229-cde4-6dec4af832dd","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PRT SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100 }\n  ],\n  \"adjustment\": { \"newReference\": { \"number\": \"{{purchaseReturnReference}}\" } },\n  \"narration\": \"Postman test purchase return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-return-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/purchase-return-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)\n<strong>Status (2026-10-23):</strong> deployed and live (release <code>790395a</code>). The PC needs an AI Zeny version that relays purchase returns (Windows <code>3ee32d4</code> or later — <strong>not</strong> in public release 0.0.12); an earlier version answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>returnReference</code>, <code>date</code>, <code>voucherNumber</code>, <code>supplier</code>, <code>purchaseType</code>, <code>materialCenter</code>, <code>lines</code> · <strong>Optional:</strong> <code>voucherSeries</code>, <code>originalPurchase</code>, <code>adjustment</code> (required for a bill-by-bill supplier), <code>billSundries</code>, <code>narration</code>, and per line <code>discountPercent</code>, <code>parameters</code> · operation <code>busy.purchase-returns.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.</strong> Same operation, body and answer as the Local request <em>Local PC → ⚠ Voucher Create → ⚠ BUSY purchase return – create</em>, called through the Cloud Relay with the same organization token that reads: a <strong>purchase return (debit note)</strong> — the supplier is debited, purchase and GST inputs credited, the goods leave <code>materialCenter</code>. Create only. SQL Server companies with a SQL login, and Access companies (Windows <code>6c5776d</code> or later; an earlier PC answers Access with <code>409 MASTER_WRITE_PROVIDER_UNSUPPORTED</code>).</p>\n<p><strong>Identities:</strong> <code>returnReference</code> (yours, 1-60, unique among the company's purchase returns of the year → <code>409 PURCHASE_RETURN_REFERENCE_TAKEN</code> + <code>details.purchaseReturnId</code>); <code>voucherNumber</code> (required, 1-25, your debit-note number, new in a <strong>manually</strong> numbered series → <code>409 PURCHASE_RETURN_NUMBER_TAKEN</code>; also recorded as the return's own bill number).</p>\n<p><strong>Original purchase and returnable quantity:</strong> <code>originalPurchase</code> = <code>{ \"voucherId\": n }</code> or <code>{ \"supplierInvoiceNumber\": \"…\" }</code> (the supplier's one non-cancelled purchase). The ceiling per item (and parameter value) is purchased less the supplier's earlier returns attributable to it (<code>422 PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE</code>); a history that cannot be attributed is refused (<code>422 PURCHASE_RETURN_HISTORY_AMBIGUOUS</code>), never guessed. <strong>Limitation:</strong> without <code>originalPurchase</code> there is <strong>no</strong> original-purchase ceiling, and an earlier return that names no purchase is never attributed to one.</p>\n<p><strong>Allocation (<code>adjustment</code>):</strong> required for a supplier BUSY keeps bill by bill (<code>422 PURCHASE_RETURN_ADJUSTMENT_REQUIRED</code>), refused for any other (<code>422 PURCHASE_RETURN_ADJUSTMENT_UNSUPPORTED</code>); it allocates the <strong>whole total</strong>: <code>againstOriginalPurchase { amount? }</code> (needs <code>originalPurchase</code>; default the smaller of the total and what the original's payable still owes; never more → <code>422 PURCHASE_RETURN_BILL_OVERSETTLED</code>) and/or <code>newReference { number }</code> (a number none of the supplier's bill rows carries → else <code>409 PURCHASE_RETURN_NEW_REFERENCE_TAKEN</code>; due on the return's date — its own <code>dueDate</code> is refused <code>422 PURCHASE_RETURN_ADJUSTMENT_UNSUPPORTED</code> in the cloud).</p>\n<p><strong>Body rules:</strong> lines 1-100 with the purchase's rules (quantity at most 2 decimals, rate and net rate 2 decimals, <code>parameters</code> for parameter-wise items → <code>422 PURCHASE_RETURN_PARAMETERS_INVALID</code>), no <code>mrp</code> or <code>description</code>; <code>billSundries</code> (≤ 10): fixed charges <code>{ billSundry, amount }</code> and at most one Rounded Off (-) ≤ 0.99 — a discount by <code>percent</code> is refused <code>422 PURCHASE_RETURN_BILL_SUNDRY_UNSUPPORTED</code> in the cloud. Stock below zero is not checked. Body ≤ <strong>128 KiB</strong>.</p>\n<p><strong>Idempotency-Key lifecycle (Postman):</strong> as every Cloud write here — minted only when none is held, <strong>kept</strong> after any <code>504</code> or <code>409 REQUEST_IN_PROGRESS</code> / <code>IDEMPOTENT_REPLAY_UNAVAILABLE</code> / <code>IDEMPOTENCY_KEY_REUSED</code>, cleared after a definite answer; never a fresh <code>b5b12d73-ac08-458e-ad7d-217f245be5bd</code> per send.</p>\n<p><strong>Uncertain writes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> or <code>504 BUSY_WRITE_UNCERTAIN</code> look the return up by <code>returnReference</code>; to recover deliberately unset <code>cloudIdempotencyKey</code> and resend the same body: if the first one saved, the answer is <code>409 PURCHASE_RETURN_REFERENCE_TAKEN</code> with <code>details.purchaseReturnId</code>. <code>502 BUSY_WRITE_UNVERIFIED</code> = saved, read-back differs: check it in BUSY. Only <code>503 BUSY_COM_QUEUE_TIMEOUT</code> is retryable.</p>\n<p><strong>Other errors:</strong> <code>404 PURCHASE_RETURN_ORIGINAL_NOT_FOUND</code>; <code>409 PURCHASE_RETURN_MASTER_CHANGED</code>; <code>422 PURCHASE_RETURN_ORIGINAL_MISMATCH</code>, <code>_ORIGINAL_CANCELLED</code>, <code>_ORIGINAL_AMBIGUOUS</code>, <code>_DATE_BEFORE_ORIGINAL</code>, <code>_BILL_NOT_FOUND</code>, <code>_SERIES_UNSUPPORTED</code>, <code>_SUPPLIER_UNSUPPORTED</code>, <code>_TYPE_UNSUPPORTED</code>, <code>_TAX_UNSUPPORTED</code>, <code>_ITEM_UNSUPPORTED</code>, <code>MASTER_REFERENCE_NOT_FOUND</code> / <code>_AMBIGUOUS</code>; <code>502 BUSY_WRITE_FAILED</code>.</p>\n<p><strong>Safe test guidance:</strong> development-test company only, a <strong>new, unique</strong> <code>purchaseReturnReference</code> of at most 25 characters (current value; also the voucher number and the new reference's number). A created return stays in BUSY. Saved examples are synthetic.</p>\n<p><strong>Durable queue:</strong> optional strict <code>queue</code> (omitted or <code>false</code>: synchronous; <code>true</code>: a <code>202</code> job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.</p>\n<hr />\n<p><strong>Parity update (2026-10-23, deployed in release <code>790395a</code>; the PC must be Windows <code>6c5776d</code> or later for these members).</strong> This request's body sends only the basic members. New optional members and codes:</p>\n<ul>\n<li><code>queue</code> (optional, <code>true</code> or <code>false</code>, default <code>false</code>; <code>null</code> is refused <code>400</code>): with <code>true</code> the PC accepts the write on its durable queue and the answer is <strong><code>202</code></strong> with <code>data: null</code> and <code>metadata.queued: true</code>, <code>metadata.jobId</code> (32 hex), <code>metadata.status</code> — acceptance, <strong>not</strong> a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable <code>companyCode</code>/four-digit <code>financialYear</code>; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (<code>202</code>) and fails there. The cloud sends it once.</li>\n<li>GST modes: <code>taxCalculation</code> (<code>auto</code> default, or <code>manual</code>) and <code>pricingMode</code> (<code>gstExclusive</code> default, or <code>gstInclusive</code>, which must match the voucher type's inclusive flag). Manual needs every line's <code>amounts { taxableAmount, cgst, sgst, igst, amount }</code> and the voucher <code>totals</code> (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: <code>422 GST_AMOUNTS_INVALID</code>, <code>422 GST_MODE_UNSUPPORTED</code>, <code>409 GST_CONFIGURATION_CHANGED</code>. A new mode with <code>originalPurchase</code>, an adjustment, <code>billSundries</code> or parameter-wise stock is <code>422 GST_MODE_UNSUPPORTED</code>.</li>\n<li>Shared refusals of every write, answered before anything is written: <code>403 PLAN_FEATURE_NOT_INCLUDED</code>, <code>409 PLAN_NOT_KNOWN</code>, <code>503 BUSY_COM_RECOVERY_REQUIRED</code>, <code>409 BUSY_WRITE_TARGET_CHANGED</code>, <code>422 BUSY_SETTING_REQUIRED</code>, <code>502 BUSY_SETTINGS_UNREADABLE</code>; queue refusals <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>, <code>503 WRITE_QUEUE_UNAVAILABLE</code>.</li>\n</ul>\n<p>Scenario requests for the new members are in this folder, named <code>⚠ Scenario – …</code> and <code>⚠ EXPECTED REFUSAL …</code>; they are guarded like this one (<code>confirmMutating</code> = <code>yes</code>, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Cloud Relay has not deployed the new numbering schema; these are documentation examples only. Do not Send until Cloud parity is deployed and verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"0007-A\",\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PRT SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100\n    }\n  ],\n  \"adjustment\": {\n    \"newReference\": {\n      \"number\": \"{{purchaseReturnReference}}\"\n    }\n  },\n  \"narration\": \"Postman test purchase return\",\n  \"numberingMode\": \"manual\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"supplier\": {\n    \"name\": \"AZPOC-PRT SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100\n    }\n  ],\n  \"adjustment\": {\n    \"newReference\": {\n      \"number\": \"{{purchaseReturnReference}}\"\n    }\n  },\n  \"narration\": \"Postman test purchase return\",\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","urlObject":{"path":["v1","purchase-return-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"b8ffaef7-4455-3eaf-4abf-9315fa3eed47","name":"200 – purchase return created: against the original + new reference [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PRT SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100 }\n  ],\n  \"adjustment\": { \"newReference\": { \"number\": \"{{purchaseReturnReference}}\" } },\n  \"narration\": \"Postman test purchase return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-return-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/purchase-return-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays purchase returns (Windows `3ee32d4` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `voucherNumber`, `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalPurchase`, `adjustment` (required for a bill-by-bill supplier), `billSundries`, `narration`, and per line `discountPercent`, `parameters` · operation `busy.purchase-returns.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY purchase return – create*, called through the Cloud Relay with the same organization token that reads: a **purchase return (debit note)** — the supplier is debited, purchase and GST inputs credited, the goods leave `materialCenter`. Create only. SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Identities:** `returnReference` (yours, 1-60, unique among the company's purchase returns of the year → `409 PURCHASE_RETURN_REFERENCE_TAKEN` + `details.purchaseReturnId`); `voucherNumber` (required, 1-25, your debit-note number, new in a **manually** numbered series → `409 PURCHASE_RETURN_NUMBER_TAKEN`; also recorded as the return's own bill number).\n\n**Original purchase and returnable quantity:** `originalPurchase` = `{ \"voucherId\": n }` or `{ \"supplierInvoiceNumber\": \"…\" }` (the supplier's one non-cancelled purchase). The ceiling per item (and parameter value) is purchased less the supplier's earlier returns attributable to it (`422 PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE`); a history that cannot be attributed is refused (`422 PURCHASE_RETURN_HISTORY_AMBIGUOUS`), never guessed. **Limitation:** without `originalPurchase` there is **no** original-purchase ceiling, and an earlier return that names no purchase is never attributed to one.\n\n**Allocation (`adjustment`):** required for a supplier BUSY keeps bill by bill (`422 PURCHASE_RETURN_ADJUSTMENT_REQUIRED`), refused for any other (`422 PURCHASE_RETURN_ADJUSTMENT_UNSUPPORTED`); it allocates the **whole total**: `againstOriginalPurchase { amount? }` (needs `originalPurchase`; default the smaller of the total and what the original's payable still owes; never more → `422 PURCHASE_RETURN_BILL_OVERSETTLED`) and/or `newReference { number }` (a number none of the supplier's bill rows carries → else `409 PURCHASE_RETURN_NEW_REFERENCE_TAKEN`; due on the return's date — its own `dueDate` is refused `422 PURCHASE_RETURN_ADJUSTMENT_UNSUPPORTED` in the cloud).\n\n**Body rules:** lines 1-100 with the purchase's rules (quantity at most 2 decimals, rate and net rate 2 decimals, `parameters` for parameter-wise items → `422 PURCHASE_RETURN_PARAMETERS_INVALID`), no `mrp` or `description`; `billSundries` (≤ 10): fixed charges `{ billSundry, amount }` and at most one Rounded Off (-) ≤ 0.99 — a discount by `percent` is refused `422 PURCHASE_RETURN_BILL_SUNDRY_UNSUPPORTED` in the cloud. Stock below zero is not checked. Body ≤ **128 KiB**.\n\n**Idempotency-Key lifecycle (Postman):** as every Cloud write here — minted only when none is held, **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, cleared after a definite answer; never a fresh `a52b534a-d36e-49cd-ad5d-4aca12012e5a` per send.\n\n**Uncertain writes:** after `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` look the return up by `returnReference`; to recover deliberately unset `cloudIdempotencyKey` and resend the same body: if the first one saved, the answer is `409 PURCHASE_RETURN_REFERENCE_TAKEN` with `details.purchaseReturnId`. `502 BUSY_WRITE_UNVERIFIED` = saved, read-back differs: check it in BUSY. Only `503 BUSY_COM_QUEUE_TIMEOUT` is retryable.\n\n**Other errors:** `404 PURCHASE_RETURN_ORIGINAL_NOT_FOUND`; `409 PURCHASE_RETURN_MASTER_CHANGED`; `422 PURCHASE_RETURN_ORIGINAL_MISMATCH`, `_ORIGINAL_CANCELLED`, `_ORIGINAL_AMBIGUOUS`, `_DATE_BEFORE_ORIGINAL`, `_BILL_NOT_FOUND`, `_SERIES_UNSUPPORTED`, `_SUPPLIER_UNSUPPORTED`, `_TYPE_UNSUPPORTED`, `_TAX_UNSUPPORTED`, `_ITEM_UNSUPPORTED`, `MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`; `502 BUSY_WRITE_FAILED`.\n\n**Safe test guidance:** development-test company only, a **new, unique** `purchaseReturnReference` of at most 25 characters (current value; also the voucher number and the new reference's number). A created return stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `originalPurchase`, an adjustment, `billSundries` or parameter-wise stock is `422 GST_MODE_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000105"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"purchaseReturnId\": 8857,\n    \"voucherNumber\": \"DN-2207\",\n    \"returnReference\": \"WEB-PRT-50131\",\n    \"date\": \"2026-10-20\",\n    \"voucherSeries\": { \"code\": 261, \"name\": \"Main\" },\n    \"supplier\": { \"code\": 7101, \"name\": \"Synthetic Supplies\" },\n    \"purchaseType\": { \"code\": 9312, \"name\": \"Local-ItemWise\" },\n    \"taxation\": \"local\",\n    \"materialCenter\": { \"code\": 9501, \"name\": \"Main Store\" },\n    \"originalPurchase\": { \"purchaseId\": 8840, \"supplierInvoiceNumber\": \"SUP-7781\", \"date\": \"2026-10-15\" },\n    \"lines\": [\n      { \"lineNumber\": 1, \"item\": { \"code\": 9401, \"name\": \"Synthetic Item\" }, \"unit\": \"Pcs.\", \"quantity\": 4, \"rate\": 120, \"discountPercent\": 0, \"netRate\": 120, \"taxableAmount\": 480, \"cgst\": 28.8, \"sgst\": 28.8, \"igst\": 0, \"taxAmount\": 57.6, \"amount\": 537.6, \"cost\": 480, \"parameters\": [] },\n      { \"lineNumber\": 2, \"item\": { \"code\": 9402, \"name\": \"Synthetic Colour Item\" }, \"unit\": \"Pcs.\", \"quantity\": 2, \"rate\": 80, \"discountPercent\": 0, \"netRate\": 80, \"taxableAmount\": 160, \"cgst\": 9.6, \"sgst\": 9.6, \"igst\": 0, \"taxAmount\": 19.2, \"amount\": 179.2, \"cost\": 160, \"parameters\": [{ \"value\": \"RED\", \"quantity\": 2, \"amount\": 160 }] }\n    ],\n    \"billSundries\": [\n      { \"lineNumber\": 1, \"billSundry\": { \"code\": 9602, \"name\": \"Freight & Forwarding Charges\" }, \"kind\": \"charge\", \"percent\": null, \"baseAmount\": null, \"amount\": 20, \"effect\": \"add\" },\n      { \"lineNumber\": 2, \"billSundry\": { \"code\": 9604, \"name\": \"Rounded Off (-)\" }, \"kind\": \"roundOff\", \"percent\": null, \"baseAmount\": null, \"amount\": 0.8, \"effect\": \"subtract\" }\n    ],\n    \"totals\": { \"quantity\": 6, \"taxableAmount\": 640, \"cgst\": 38.4, \"sgst\": 38.4, \"igst\": 0, \"taxAmount\": 76.8, \"charges\": 20, \"roundOff\": -0.8, \"purchaseValue\": 640, \"amount\": 736 },\n    \"allocations\": [\n      { \"type\": \"againstOriginalPurchase\", \"number\": \"SUP-7781\", \"amount\": 600, \"outstandingBefore\": 1806, \"outstandingAfter\": 1206, \"dueDate\": \"2026-11-14\" },\n      { \"type\": \"newReference\", \"number\": \"DN-2207\", \"amount\": 136, \"outstandingBefore\": null, \"outstandingAfter\": -136, \"dueDate\": \"2026-10-20\" }\n    ],\n    \"narration\": \"Synthetic return of damaged goods\",\n    \"ledger\": [\n      { \"account\": { \"code\": 7101, \"name\": \"Synthetic Supplies\" }, \"debit\": 736, \"credit\": 0 },\n      { \"account\": { \"code\": 9201, \"name\": \"Synthetic Purchase\" }, \"debit\": 0, \"credit\": 640 },\n      { \"account\": { \"code\": 9221, \"name\": \"Synthetic Freight\" }, \"debit\": 0, \"credit\": 20 },\n      { \"account\": { \"code\": 9231, \"name\": \"Synthetic Round Off\" }, \"debit\": 0.8, \"credit\": 0 },\n      { \"account\": { \"code\": 9213, \"name\": \"Synthetic CGST Input\" }, \"debit\": 0, \"credit\": 38.4 },\n      { \"account\": { \"code\": 9214, \"name\": \"Synthetic SGST Input\" }, \"debit\": 0, \"credit\": 38.4 }\n    ]\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.purchase-returns.create\",\n    \"requestId\": \"rq_0SYNTHET1C0000000000000105\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"lineCount\": 2,\n    \"verification\": [\"busyReadBack\", \"savedRows\"],\n    \"elapsedMs\": 3105,\n    \"executedAt\": \"2026-10-20T06:30:00+00:00\"\n  }\n}"},{"id":"29b76790-69ef-ce65-c43b-f4d258558256","name":"409 – PURCHASE_RETURN_REFERENCE_TAKEN: a resend after a saved return (details.purchaseReturnId) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PRT SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100 }\n  ],\n  \"adjustment\": { \"newReference\": { \"number\": \"{{purchaseReturnReference}}\" } },\n  \"narration\": \"Postman test purchase return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-return-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/purchase-return-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays purchase returns (Windows `3ee32d4` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `voucherNumber`, `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalPurchase`, `adjustment` (required for a bill-by-bill supplier), `billSundries`, `narration`, and per line `discountPercent`, `parameters` · operation `busy.purchase-returns.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY purchase return – create*, called through the Cloud Relay with the same organization token that reads: a **purchase return (debit note)** — the supplier is debited, purchase and GST inputs credited, the goods leave `materialCenter`. Create only. SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Identities:** `returnReference` (yours, 1-60, unique among the company's purchase returns of the year → `409 PURCHASE_RETURN_REFERENCE_TAKEN` + `details.purchaseReturnId`); `voucherNumber` (required, 1-25, your debit-note number, new in a **manually** numbered series → `409 PURCHASE_RETURN_NUMBER_TAKEN`; also recorded as the return's own bill number).\n\n**Original purchase and returnable quantity:** `originalPurchase` = `{ \"voucherId\": n }` or `{ \"supplierInvoiceNumber\": \"…\" }` (the supplier's one non-cancelled purchase). The ceiling per item (and parameter value) is purchased less the supplier's earlier returns attributable to it (`422 PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE`); a history that cannot be attributed is refused (`422 PURCHASE_RETURN_HISTORY_AMBIGUOUS`), never guessed. **Limitation:** without `originalPurchase` there is **no** original-purchase ceiling, and an earlier return that names no purchase is never attributed to one.\n\n**Allocation (`adjustment`):** required for a supplier BUSY keeps bill by bill (`422 PURCHASE_RETURN_ADJUSTMENT_REQUIRED`), refused for any other (`422 PURCHASE_RETURN_ADJUSTMENT_UNSUPPORTED`); it allocates the **whole total**: `againstOriginalPurchase { amount? }` (needs `originalPurchase`; default the smaller of the total and what the original's payable still owes; never more → `422 PURCHASE_RETURN_BILL_OVERSETTLED`) and/or `newReference { number }` (a number none of the supplier's bill rows carries → else `409 PURCHASE_RETURN_NEW_REFERENCE_TAKEN`; due on the return's date — its own `dueDate` is refused `422 PURCHASE_RETURN_ADJUSTMENT_UNSUPPORTED` in the cloud).\n\n**Body rules:** lines 1-100 with the purchase's rules (quantity at most 2 decimals, rate and net rate 2 decimals, `parameters` for parameter-wise items → `422 PURCHASE_RETURN_PARAMETERS_INVALID`), no `mrp` or `description`; `billSundries` (≤ 10): fixed charges `{ billSundry, amount }` and at most one Rounded Off (-) ≤ 0.99 — a discount by `percent` is refused `422 PURCHASE_RETURN_BILL_SUNDRY_UNSUPPORTED` in the cloud. Stock below zero is not checked. Body ≤ **128 KiB**.\n\n**Idempotency-Key lifecycle (Postman):** as every Cloud write here — minted only when none is held, **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, cleared after a definite answer; never a fresh `3a193555-d08a-421b-a232-e1dc88fd8533` per send.\n\n**Uncertain writes:** after `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` look the return up by `returnReference`; to recover deliberately unset `cloudIdempotencyKey` and resend the same body: if the first one saved, the answer is `409 PURCHASE_RETURN_REFERENCE_TAKEN` with `details.purchaseReturnId`. `502 BUSY_WRITE_UNVERIFIED` = saved, read-back differs: check it in BUSY. Only `503 BUSY_COM_QUEUE_TIMEOUT` is retryable.\n\n**Other errors:** `404 PURCHASE_RETURN_ORIGINAL_NOT_FOUND`; `409 PURCHASE_RETURN_MASTER_CHANGED`; `422 PURCHASE_RETURN_ORIGINAL_MISMATCH`, `_ORIGINAL_CANCELLED`, `_ORIGINAL_AMBIGUOUS`, `_DATE_BEFORE_ORIGINAL`, `_BILL_NOT_FOUND`, `_SERIES_UNSUPPORTED`, `_SUPPLIER_UNSUPPORTED`, `_TYPE_UNSUPPORTED`, `_TAX_UNSUPPORTED`, `_ITEM_UNSUPPORTED`, `MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`; `502 BUSY_WRITE_FAILED`.\n\n**Safe test guidance:** development-test company only, a **new, unique** `purchaseReturnReference` of at most 25 characters (current value; also the voucher number and the new reference's number). A created return stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `originalPurchase`, an adjustment, `billSundries` or parameter-wise stock is `422 GST_MODE_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000106","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PURCHASE_RETURN_REFERENCE_TAKEN\",\n      \"message\": \"A purchase return of this company and financial year already holds this returnReference. A create never changes an existing return; if your earlier call saved it, metadata.error.details.purchaseReturnId names it.\",\n      \"field\": \"returnReference\",\n      \"details\": { \"purchaseReturnId\": 8857 }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000106\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"b1433a20-52c9-8f7a-4d5f-60ddc75592c1","name":"422 – PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE: more than the original still has [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PRT SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100 }\n  ],\n  \"adjustment\": { \"newReference\": { \"number\": \"{{purchaseReturnReference}}\" } },\n  \"narration\": \"Postman test purchase return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-return-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/purchase-return-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays purchase returns (Windows `3ee32d4` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `voucherNumber`, `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalPurchase`, `adjustment` (required for a bill-by-bill supplier), `billSundries`, `narration`, and per line `discountPercent`, `parameters` · operation `busy.purchase-returns.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY purchase return – create*, called through the Cloud Relay with the same organization token that reads: a **purchase return (debit note)** — the supplier is debited, purchase and GST inputs credited, the goods leave `materialCenter`. Create only. SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Identities:** `returnReference` (yours, 1-60, unique among the company's purchase returns of the year → `409 PURCHASE_RETURN_REFERENCE_TAKEN` + `details.purchaseReturnId`); `voucherNumber` (required, 1-25, your debit-note number, new in a **manually** numbered series → `409 PURCHASE_RETURN_NUMBER_TAKEN`; also recorded as the return's own bill number).\n\n**Original purchase and returnable quantity:** `originalPurchase` = `{ \"voucherId\": n }` or `{ \"supplierInvoiceNumber\": \"…\" }` (the supplier's one non-cancelled purchase). The ceiling per item (and parameter value) is purchased less the supplier's earlier returns attributable to it (`422 PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE`); a history that cannot be attributed is refused (`422 PURCHASE_RETURN_HISTORY_AMBIGUOUS`), never guessed. **Limitation:** without `originalPurchase` there is **no** original-purchase ceiling, and an earlier return that names no purchase is never attributed to one.\n\n**Allocation (`adjustment`):** required for a supplier BUSY keeps bill by bill (`422 PURCHASE_RETURN_ADJUSTMENT_REQUIRED`), refused for any other (`422 PURCHASE_RETURN_ADJUSTMENT_UNSUPPORTED`); it allocates the **whole total**: `againstOriginalPurchase { amount? }` (needs `originalPurchase`; default the smaller of the total and what the original's payable still owes; never more → `422 PURCHASE_RETURN_BILL_OVERSETTLED`) and/or `newReference { number }` (a number none of the supplier's bill rows carries → else `409 PURCHASE_RETURN_NEW_REFERENCE_TAKEN`; due on the return's date — its own `dueDate` is refused `422 PURCHASE_RETURN_ADJUSTMENT_UNSUPPORTED` in the cloud).\n\n**Body rules:** lines 1-100 with the purchase's rules (quantity at most 2 decimals, rate and net rate 2 decimals, `parameters` for parameter-wise items → `422 PURCHASE_RETURN_PARAMETERS_INVALID`), no `mrp` or `description`; `billSundries` (≤ 10): fixed charges `{ billSundry, amount }` and at most one Rounded Off (-) ≤ 0.99 — a discount by `percent` is refused `422 PURCHASE_RETURN_BILL_SUNDRY_UNSUPPORTED` in the cloud. Stock below zero is not checked. Body ≤ **128 KiB**.\n\n**Idempotency-Key lifecycle (Postman):** as every Cloud write here — minted only when none is held, **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, cleared after a definite answer; never a fresh `92d8fb88-8968-4513-a9a5-5baf6944dcc5` per send.\n\n**Uncertain writes:** after `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` look the return up by `returnReference`; to recover deliberately unset `cloudIdempotencyKey` and resend the same body: if the first one saved, the answer is `409 PURCHASE_RETURN_REFERENCE_TAKEN` with `details.purchaseReturnId`. `502 BUSY_WRITE_UNVERIFIED` = saved, read-back differs: check it in BUSY. Only `503 BUSY_COM_QUEUE_TIMEOUT` is retryable.\n\n**Other errors:** `404 PURCHASE_RETURN_ORIGINAL_NOT_FOUND`; `409 PURCHASE_RETURN_MASTER_CHANGED`; `422 PURCHASE_RETURN_ORIGINAL_MISMATCH`, `_ORIGINAL_CANCELLED`, `_ORIGINAL_AMBIGUOUS`, `_DATE_BEFORE_ORIGINAL`, `_BILL_NOT_FOUND`, `_SERIES_UNSUPPORTED`, `_SUPPLIER_UNSUPPORTED`, `_TYPE_UNSUPPORTED`, `_TAX_UNSUPPORTED`, `_ITEM_UNSUPPORTED`, `MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`; `502 BUSY_WRITE_FAILED`.\n\n**Safe test guidance:** development-test company only, a **new, unique** `purchaseReturnReference` of at most 25 characters (current value; also the voucher number and the new reference's number). A created return stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `originalPurchase`, an adjustment, `billSundries` or parameter-wise stock is `422 GST_MODE_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000107"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE\",\n      \"message\": \"This line returns more of the item than the original purchase still has to return (its quantity less the earlier returns that name it).\",\n      \"field\": \"lines[0].quantity\"\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000107\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"6036f6f4-a419-0bdb-0c8d-669acadee624","name":"422 – PURCHASE_RETURN_ADJUSTMENT_UNSUPPORTED: a new reference's own dueDate (refused by the cloud) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PRT SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100 }\n  ],\n  \"adjustment\": { \"newReference\": { \"number\": \"{{purchaseReturnReference}}\" } },\n  \"narration\": \"Postman test purchase return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-return-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/purchase-return-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays purchase returns (Windows `3ee32d4` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `voucherNumber`, `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalPurchase`, `adjustment` (required for a bill-by-bill supplier), `billSundries`, `narration`, and per line `discountPercent`, `parameters` · operation `busy.purchase-returns.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY purchase return – create*, called through the Cloud Relay with the same organization token that reads: a **purchase return (debit note)** — the supplier is debited, purchase and GST inputs credited, the goods leave `materialCenter`. Create only. SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Identities:** `returnReference` (yours, 1-60, unique among the company's purchase returns of the year → `409 PURCHASE_RETURN_REFERENCE_TAKEN` + `details.purchaseReturnId`); `voucherNumber` (required, 1-25, your debit-note number, new in a **manually** numbered series → `409 PURCHASE_RETURN_NUMBER_TAKEN`; also recorded as the return's own bill number).\n\n**Original purchase and returnable quantity:** `originalPurchase` = `{ \"voucherId\": n }` or `{ \"supplierInvoiceNumber\": \"…\" }` (the supplier's one non-cancelled purchase). The ceiling per item (and parameter value) is purchased less the supplier's earlier returns attributable to it (`422 PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE`); a history that cannot be attributed is refused (`422 PURCHASE_RETURN_HISTORY_AMBIGUOUS`), never guessed. **Limitation:** without `originalPurchase` there is **no** original-purchase ceiling, and an earlier return that names no purchase is never attributed to one.\n\n**Allocation (`adjustment`):** required for a supplier BUSY keeps bill by bill (`422 PURCHASE_RETURN_ADJUSTMENT_REQUIRED`), refused for any other (`422 PURCHASE_RETURN_ADJUSTMENT_UNSUPPORTED`); it allocates the **whole total**: `againstOriginalPurchase { amount? }` (needs `originalPurchase`; default the smaller of the total and what the original's payable still owes; never more → `422 PURCHASE_RETURN_BILL_OVERSETTLED`) and/or `newReference { number }` (a number none of the supplier's bill rows carries → else `409 PURCHASE_RETURN_NEW_REFERENCE_TAKEN`; due on the return's date — its own `dueDate` is refused `422 PURCHASE_RETURN_ADJUSTMENT_UNSUPPORTED` in the cloud).\n\n**Body rules:** lines 1-100 with the purchase's rules (quantity at most 2 decimals, rate and net rate 2 decimals, `parameters` for parameter-wise items → `422 PURCHASE_RETURN_PARAMETERS_INVALID`), no `mrp` or `description`; `billSundries` (≤ 10): fixed charges `{ billSundry, amount }` and at most one Rounded Off (-) ≤ 0.99 — a discount by `percent` is refused `422 PURCHASE_RETURN_BILL_SUNDRY_UNSUPPORTED` in the cloud. Stock below zero is not checked. Body ≤ **128 KiB**.\n\n**Idempotency-Key lifecycle (Postman):** as every Cloud write here — minted only when none is held, **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, cleared after a definite answer; never a fresh `c812e7fc-170c-466a-b843-8309af524b20` per send.\n\n**Uncertain writes:** after `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` look the return up by `returnReference`; to recover deliberately unset `cloudIdempotencyKey` and resend the same body: if the first one saved, the answer is `409 PURCHASE_RETURN_REFERENCE_TAKEN` with `details.purchaseReturnId`. `502 BUSY_WRITE_UNVERIFIED` = saved, read-back differs: check it in BUSY. Only `503 BUSY_COM_QUEUE_TIMEOUT` is retryable.\n\n**Other errors:** `404 PURCHASE_RETURN_ORIGINAL_NOT_FOUND`; `409 PURCHASE_RETURN_MASTER_CHANGED`; `422 PURCHASE_RETURN_ORIGINAL_MISMATCH`, `_ORIGINAL_CANCELLED`, `_ORIGINAL_AMBIGUOUS`, `_DATE_BEFORE_ORIGINAL`, `_BILL_NOT_FOUND`, `_SERIES_UNSUPPORTED`, `_SUPPLIER_UNSUPPORTED`, `_TYPE_UNSUPPORTED`, `_TAX_UNSUPPORTED`, `_ITEM_UNSUPPORTED`, `MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`; `502 BUSY_WRITE_FAILED`.\n\n**Safe test guidance:** development-test company only, a **new, unique** `purchaseReturnReference` of at most 25 characters (current value; also the voucher number and the new reference's number). A created return stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `originalPurchase`, an adjustment, `billSundries` or parameter-wise stock is `422 GST_MODE_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PURCHASE_RETURN_ADJUSTMENT_UNSUPPORTED\",\n      \"message\": \"A due date of its own for a new debit reference is not offered in this version: BUSY dates it on the return's date. Leave dueDate out.\",\n      \"field\": \"adjustment.newReference.dueDate\"\n    },\n    \"requestId\": \"00000000-5e5e-4000-8000-000000000104\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"1b36962b-1eae-cf7a-3bb8-4906c9415217","name":"504 – WRITE_RESULT_UNKNOWN: the PC's answer was lost (key kept; look up by returnReference) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PRT SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100 }\n  ],\n  \"adjustment\": { \"newReference\": { \"number\": \"{{purchaseReturnReference}}\" } },\n  \"narration\": \"Postman test purchase return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-return-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/purchase-return-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays purchase returns (Windows `3ee32d4` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `voucherNumber`, `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalPurchase`, `adjustment` (required for a bill-by-bill supplier), `billSundries`, `narration`, and per line `discountPercent`, `parameters` · operation `busy.purchase-returns.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY purchase return – create*, called through the Cloud Relay with the same organization token that reads: a **purchase return (debit note)** — the supplier is debited, purchase and GST inputs credited, the goods leave `materialCenter`. Create only. SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Identities:** `returnReference` (yours, 1-60, unique among the company's purchase returns of the year → `409 PURCHASE_RETURN_REFERENCE_TAKEN` + `details.purchaseReturnId`); `voucherNumber` (required, 1-25, your debit-note number, new in a **manually** numbered series → `409 PURCHASE_RETURN_NUMBER_TAKEN`; also recorded as the return's own bill number).\n\n**Original purchase and returnable quantity:** `originalPurchase` = `{ \"voucherId\": n }` or `{ \"supplierInvoiceNumber\": \"…\" }` (the supplier's one non-cancelled purchase). The ceiling per item (and parameter value) is purchased less the supplier's earlier returns attributable to it (`422 PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE`); a history that cannot be attributed is refused (`422 PURCHASE_RETURN_HISTORY_AMBIGUOUS`), never guessed. **Limitation:** without `originalPurchase` there is **no** original-purchase ceiling, and an earlier return that names no purchase is never attributed to one.\n\n**Allocation (`adjustment`):** required for a supplier BUSY keeps bill by bill (`422 PURCHASE_RETURN_ADJUSTMENT_REQUIRED`), refused for any other (`422 PURCHASE_RETURN_ADJUSTMENT_UNSUPPORTED`); it allocates the **whole total**: `againstOriginalPurchase { amount? }` (needs `originalPurchase`; default the smaller of the total and what the original's payable still owes; never more → `422 PURCHASE_RETURN_BILL_OVERSETTLED`) and/or `newReference { number }` (a number none of the supplier's bill rows carries → else `409 PURCHASE_RETURN_NEW_REFERENCE_TAKEN`; due on the return's date — its own `dueDate` is refused `422 PURCHASE_RETURN_ADJUSTMENT_UNSUPPORTED` in the cloud).\n\n**Body rules:** lines 1-100 with the purchase's rules (quantity at most 2 decimals, rate and net rate 2 decimals, `parameters` for parameter-wise items → `422 PURCHASE_RETURN_PARAMETERS_INVALID`), no `mrp` or `description`; `billSundries` (≤ 10): fixed charges `{ billSundry, amount }` and at most one Rounded Off (-) ≤ 0.99 — a discount by `percent` is refused `422 PURCHASE_RETURN_BILL_SUNDRY_UNSUPPORTED` in the cloud. Stock below zero is not checked. Body ≤ **128 KiB**.\n\n**Idempotency-Key lifecycle (Postman):** as every Cloud write here — minted only when none is held, **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, cleared after a definite answer; never a fresh `9667cf1b-7201-49f2-85fa-1ea39672ebfa` per send.\n\n**Uncertain writes:** after `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` look the return up by `returnReference`; to recover deliberately unset `cloudIdempotencyKey` and resend the same body: if the first one saved, the answer is `409 PURCHASE_RETURN_REFERENCE_TAKEN` with `details.purchaseReturnId`. `502 BUSY_WRITE_UNVERIFIED` = saved, read-back differs: check it in BUSY. Only `503 BUSY_COM_QUEUE_TIMEOUT` is retryable.\n\n**Other errors:** `404 PURCHASE_RETURN_ORIGINAL_NOT_FOUND`; `409 PURCHASE_RETURN_MASTER_CHANGED`; `422 PURCHASE_RETURN_ORIGINAL_MISMATCH`, `_ORIGINAL_CANCELLED`, `_ORIGINAL_AMBIGUOUS`, `_DATE_BEFORE_ORIGINAL`, `_BILL_NOT_FOUND`, `_SERIES_UNSUPPORTED`, `_SUPPLIER_UNSUPPORTED`, `_TYPE_UNSUPPORTED`, `_TAX_UNSUPPORTED`, `_ITEM_UNSUPPORTED`, `MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`; `502 BUSY_WRITE_FAILED`.\n\n**Safe test guidance:** development-test company only, a **new, unique** `purchaseReturnReference` of at most 25 characters (current value; also the voucher number and the new reference's number). A created return stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `originalPurchase`, an adjustment, `billSundries` or parameter-wise stock is `422 GST_MODE_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000114","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"WRITE_RESULT_UNKNOWN\",\n      \"message\": \"The PC's answer to this purchase return did not reach AI Zeny, so whether BUSY saved it is not known. Look the return up by its returnReference before trying again; a retry with the same returnReference is refused if the first one saved (409 PURCHASE_RETURN_REFERENCE_TAKEN with details.purchaseReturnId).\",\n      \"details\": { \"reconciliation\": \"notChecked\" }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000114\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"b3681b5b-4e4a-6569-05a2-d939df0a7dac","name":"504 – BUSY_WRITE_UNCERTAIN, reconciled found (details.purchaseReturnId; never resend) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held.","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"returnReference\": \"{{purchaseReturnReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherNumber\": \"{{purchaseReturnReference}}\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"supplier\": { \"name\": \"AZPOC-PRT SUPP MP\" },\n  \"purchaseType\": { \"name\": \"Local-ItemWise\" },\n  \"materialCenter\": { \"name\": \"Main Store\" },\n  \"lines\": [\n    { \"item\": { \"name\": \"AZPOC-SVC ITEM 01\" }, \"quantity\": 1, \"rate\": 100 }\n  ],\n  \"adjustment\": { \"newReference\": { \"number\": \"{{purchaseReturnReference}}\" } },\n  \"narration\": \"Postman test purchase return\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-return-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/purchase-return-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays purchase returns (Windows `3ee32d4` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `returnReference`, `date`, `voucherNumber`, `supplier`, `purchaseType`, `materialCenter`, `lines` · **Optional:** `voucherSeries`, `originalPurchase`, `adjustment` (required for a bill-by-bill supplier), `billSundries`, `narration`, and per line `discountPercent`, `parameters` · operation `busy.purchase-returns.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY purchase return – create*, called through the Cloud Relay with the same organization token that reads: a **purchase return (debit note)** — the supplier is debited, purchase and GST inputs credited, the goods leave `materialCenter`. Create only. SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Identities:** `returnReference` (yours, 1-60, unique among the company's purchase returns of the year → `409 PURCHASE_RETURN_REFERENCE_TAKEN` + `details.purchaseReturnId`); `voucherNumber` (required, 1-25, your debit-note number, new in a **manually** numbered series → `409 PURCHASE_RETURN_NUMBER_TAKEN`; also recorded as the return's own bill number).\n\n**Original purchase and returnable quantity:** `originalPurchase` = `{ \"voucherId\": n }` or `{ \"supplierInvoiceNumber\": \"…\" }` (the supplier's one non-cancelled purchase). The ceiling per item (and parameter value) is purchased less the supplier's earlier returns attributable to it (`422 PURCHASE_RETURN_QUANTITY_EXCEEDS_PURCHASE`); a history that cannot be attributed is refused (`422 PURCHASE_RETURN_HISTORY_AMBIGUOUS`), never guessed. **Limitation:** without `originalPurchase` there is **no** original-purchase ceiling, and an earlier return that names no purchase is never attributed to one.\n\n**Allocation (`adjustment`):** required for a supplier BUSY keeps bill by bill (`422 PURCHASE_RETURN_ADJUSTMENT_REQUIRED`), refused for any other (`422 PURCHASE_RETURN_ADJUSTMENT_UNSUPPORTED`); it allocates the **whole total**: `againstOriginalPurchase { amount? }` (needs `originalPurchase`; default the smaller of the total and what the original's payable still owes; never more → `422 PURCHASE_RETURN_BILL_OVERSETTLED`) and/or `newReference { number }` (a number none of the supplier's bill rows carries → else `409 PURCHASE_RETURN_NEW_REFERENCE_TAKEN`; due on the return's date — its own `dueDate` is refused `422 PURCHASE_RETURN_ADJUSTMENT_UNSUPPORTED` in the cloud).\n\n**Body rules:** lines 1-100 with the purchase's rules (quantity at most 2 decimals, rate and net rate 2 decimals, `parameters` for parameter-wise items → `422 PURCHASE_RETURN_PARAMETERS_INVALID`), no `mrp` or `description`; `billSundries` (≤ 10): fixed charges `{ billSundry, amount }` and at most one Rounded Off (-) ≤ 0.99 — a discount by `percent` is refused `422 PURCHASE_RETURN_BILL_SUNDRY_UNSUPPORTED` in the cloud. Stock below zero is not checked. Body ≤ **128 KiB**.\n\n**Idempotency-Key lifecycle (Postman):** as every Cloud write here — minted only when none is held, **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, cleared after a definite answer; never a fresh `fd6475fe-9662-477c-b881-ce90d3227fc5` per send.\n\n**Uncertain writes:** after `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` look the return up by `returnReference`; to recover deliberately unset `cloudIdempotencyKey` and resend the same body: if the first one saved, the answer is `409 PURCHASE_RETURN_REFERENCE_TAKEN` with `details.purchaseReturnId`. `502 BUSY_WRITE_UNVERIFIED` = saved, read-back differs: check it in BUSY. Only `503 BUSY_COM_QUEUE_TIMEOUT` is retryable.\n\n**Other errors:** `404 PURCHASE_RETURN_ORIGINAL_NOT_FOUND`; `409 PURCHASE_RETURN_MASTER_CHANGED`; `422 PURCHASE_RETURN_ORIGINAL_MISMATCH`, `_ORIGINAL_CANCELLED`, `_ORIGINAL_AMBIGUOUS`, `_DATE_BEFORE_ORIGINAL`, `_BILL_NOT_FOUND`, `_SERIES_UNSUPPORTED`, `_SUPPLIER_UNSUPPORTED`, `_TYPE_UNSUPPORTED`, `_TAX_UNSUPPORTED`, `_ITEM_UNSUPPORTED`, `MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`; `502 BUSY_WRITE_FAILED`.\n\n**Safe test guidance:** development-test company only, a **new, unique** `purchaseReturnReference` of at most 25 characters (current value; also the voucher number and the new reference's number). A created return stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- GST modes: `taxCalculation` (`auto` default, or `manual`) and `pricingMode` (`gstExclusive` default, or `gstInclusive`, which must match the voucher type's inclusive flag). Manual needs every line's `amounts { taxableAmount, cgst, sgst, igst, amount }` and the voucher `totals` (0 or more, at most 2 decimals, exact sums; numbers reach the PC digit for digit). Codes: `422 GST_AMOUNTS_INVALID`, `422 GST_MODE_UNSUPPORTED`, `409 GST_CONFIGURATION_CHANGED`. A new mode with `originalPurchase`, an adjustment, `billSundries` or parameter-wise stock is `422 GST_MODE_UNSUPPORTED`.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000108","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"BUSY stopped while saving the purchase return; a return with this returnReference exists now (metadata.error.details.purchaseReturnId). Check it in BUSY; do not send it again.\",\n      \"details\": { \"purchaseReturnId\": 8857, \"reconciliation\": \"found\" }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000108\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"c6d4df11-4b9d-d229-cde4-6dec4af832dd"},{"name":"⚠ BUSY payment – create (writes to BUSY)","id":"1d1b3508-d669-171d-a8a8-cb3256af44a0","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"payee\": { \"name\": \"AZPM-PAY PAYEE\" },\n  \"amount\": 10,\n  \"allocations\": [\n    { \"newReference\": { \"number\": \"{{paymentReference}}\" }, \"amount\": 10 }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/payment-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/payment-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)\n<strong>Status (2026-10-23):</strong> deployed and live (release <code>790395a</code>). The PC needs an AI Zeny version that relays payments (Windows <code>a29ce8d</code> or later — <strong>not</strong> in public release 0.0.12); an earlier version answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>paymentReference</code>, <code>date</code>, <code>account</code>, <code>payee</code>, <code>amount</code> · <strong>Optional:</strong> <code>voucherNumber</code> (required when <code>paymentReference</code> is longer than 25 characters), <code>voucherSeries</code>, <code>allocations</code>, <code>instrumentNumber</code>, <code>shortNarration</code>, <code>narration</code> · operation <code>busy.payments.create</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it (errors: <code>success: false</code>, <code>data: null</code>, <code>metadata.error</code>).</p>\n<hr />\n<p><strong>Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.</strong> Same operation, body and answer as the Local request <em>Local PC → ⚠ Voucher Create → ⚠ BUSY payment – create</em>, called through the Cloud Relay with the same organization token that reads. <strong>An accounting entry only: AI Zeny never pays, transfers or issues anything.</strong> One cash-in-hand, bank or bank OD <code>account</code> pays (is credited) <code>amount</code> to one <code>payee</code> (debited); a cash ↔ bank transfer is a contra, not a payment (<code>422 PAYMENT_ACCOUNT_UNSUPPORTED</code>). SQL Server companies with a SQL login, and Access companies (Windows <code>6c5776d</code> or later; an earlier PC answers Access with <code>409 MASTER_WRITE_PROVIDER_UNSUPPORTED</code>).</p>\n<p><strong>Negative balances (owner decision PY-10):</strong> a payment is <strong>never refused for an insufficient balance</strong> — it may leave Cash, Bank or Bank OD negative — and <code>data.accountBalanceAfter { asOfDate, balance, side }</code> returns the paying account's balance at the end of the payment date (this payment included; later-dated vouchers not). Positive = funds held (<code>debit</code>), negative = overdrawn (<code>credit</code>).</p>\n<p><strong>Identities:</strong> <code>paymentReference</code> (yours, 1-60, unique among the company's payments of the year → <code>409 PAYMENT_REFERENCE_TAKEN</code> + <code>details.paymentId</code>); <code>voucherNumber</code> (1-25, default <code>paymentReference</code> when it fits 25 characters; new in a <strong>manually</strong> numbered series → <code>409 PAYMENT_NUMBER_TAKEN</code>; automatic series <code>422 PAYMENT_SERIES_UNSUPPORTED</code>; <code>metadata.voucherNumberSource</code> says which).</p>\n<p><strong>Allocations</strong> (optional, 1-100, only for a payee BUSY keeps bill by bill, else <code>422 PAYMENT_ALLOCATION_UNSUPPORTED</code>): each <code>{ \"bill\": { \"number\" } }</code> (one of the payee's own outstanding bills; never over-settled → <code>422 PAYMENT_BILL_NOT_FOUND</code> / <code>PAYMENT_BILL_OVERSETTLED</code>) or <code>{ \"newReference\": { \"number\", \"dueDate\" } }</code> (an advance under a number new to the payee → else <code>409 PAYMENT_NEW_REFERENCE_TAKEN</code>; <code>dueDate</code> on or after <code>date</code>, ≤ 5 years, default <code>date</code>), with an <code>amount</code> &gt; 0 (2 decimals); each number once; together <strong>at most</strong> <code>amount</code> (the rest stays on account). <code>amount</code> &gt; 0, ≤ 9999999999.99, 2 decimals. <code>instrumentNumber</code> 1-30 is a record only. Body ≤ <strong>64 KiB</strong>.</p>\n<p><strong>Idempotency-Key lifecycle (Postman):</strong> minted only when none is held, <strong>kept</strong> after any <code>504</code> or <code>409 REQUEST_IN_PROGRESS</code> / <code>IDEMPOTENT_REPLAY_UNAVAILABLE</code> / <code>IDEMPOTENCY_KEY_REUSED</code>, cleared after a definite answer; never a fresh <code>52b2a47e-63de-4017-bc08-028ade6e9bb2</code> per send.</p>\n<p><strong>Uncertain writes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> or <code>504 BUSY_WRITE_UNCERTAIN</code> look the payment up by <code>paymentReference</code>; to recover deliberately unset <code>cloudIdempotencyKey</code> and resend the same body: if the first one saved, the answer is <code>409 PAYMENT_REFERENCE_TAKEN</code> with <code>details.paymentId</code>. <code>502 BUSY_WRITE_UNVERIFIED</code> = saved, read-back differs: check it in BUSY. Only <code>503 BUSY_COM_QUEUE_TIMEOUT</code> is retryable.</p>\n<p><strong>Other errors:</strong> <code>409 PAYMENT_MASTER_CHANGED</code>, <code>MASTER_WRITE_PROVIDER_UNSUPPORTED</code>; <code>422 MASTER_REFERENCE_NOT_FOUND</code> / <code>_AMBIGUOUS</code>, <code>BUSY_DATA_INCONSISTENT</code>; <code>502 BUSY_WRITE_FAILED</code>.</p>\n<p><strong>Safe test guidance:</strong> development-test company only, a dedicated test payee and a <strong>new, unique</strong> <code>paymentReference</code> of at most 25 characters (current value). A created payment stays in BUSY. Saved examples are synthetic.</p>\n<p><strong>Durable queue:</strong> optional strict <code>queue</code> (omitted or <code>false</code>: synchronous; <code>true</code>: a <code>202</code> job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.</p>\n<hr />\n<p><strong>Parity update (2026-10-23, deployed in release <code>790395a</code>; the PC must be Windows <code>6c5776d</code> or later for these members).</strong> This request's body sends only the basic members. New optional members and codes:</p>\n<ul>\n<li><code>queue</code> (optional, <code>true</code> or <code>false</code>, default <code>false</code>; <code>null</code> is refused <code>400</code>): with <code>true</code> the PC accepts the write on its durable queue and the answer is <strong><code>202</code></strong> with <code>data: null</code> and <code>metadata.queued: true</code>, <code>metadata.jobId</code> (32 hex), <code>metadata.status</code> — acceptance, <strong>not</strong> a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable <code>companyCode</code>/four-digit <code>financialYear</code>; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (<code>202</code>) and fails there. The cloud sends it once.</li>\n<li>Shared refusals of every write, answered before anything is written: <code>403 PLAN_FEATURE_NOT_INCLUDED</code>, <code>409 PLAN_NOT_KNOWN</code>, <code>503 BUSY_COM_RECOVERY_REQUIRED</code>, <code>409 BUSY_WRITE_TARGET_CHANGED</code>, <code>422 BUSY_SETTING_REQUIRED</code>, <code>502 BUSY_SETTINGS_UNREADABLE</code>; queue refusals <code>409 WRITE_QUEUE_REQUEST_CONFLICT</code>, <code>503 WRITE_QUEUE_UNAVAILABLE</code>.</li>\n</ul>\n<p>Scenario requests for the new members are in this folder, named <code>⚠ Scenario – …</code> and <code>⚠ EXPECTED REFUSAL …</code>; they are guarded like this one (<code>confirmMutating</code> = <code>yes</code>, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Cloud Relay has not deployed the new numbering schema; these are documentation examples only. Do not Send until Cloud parity is deployed and verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"code\": 101\n  },\n  \"account\": {\n    \"name\": \"Cash\"\n  },\n  \"payee\": {\n    \"name\": \"AZPM-PAY PAYEE\"\n  },\n  \"amount\": 10,\n  \"allocations\": [\n    {\n      \"newReference\": {\n        \"number\": \"{{paymentReference}}\"\n      },\n      \"amount\": 10\n    }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\",\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\"\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": {\n    \"code\": 102\n  },\n  \"account\": {\n    \"name\": \"Cash\"\n  },\n  \"payee\": {\n    \"name\": \"AZPM-PAY PAYEE\"\n  },\n  \"amount\": 10,\n  \"allocations\": [\n    {\n      \"newReference\": {\n        \"number\": \"{{paymentReference}}\"\n      },\n      \"amount\": 10\n    }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\",\n  \"numberingMode\": \"auto\"\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","urlObject":{"path":["v1","payment-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"6b68f013-5fe3-9e7c-8057-a6f7c994f7e9","name":"200 – payment created; the bank left overdrawn and still paid (PY-10, accountBalanceAfter negative) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held."}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"payee\": { \"name\": \"AZPM-PAY PAYEE\" },\n  \"amount\": 10,\n  \"allocations\": [\n    { \"newReference\": { \"number\": \"{{paymentReference}}\" }, \"amount\": 10 }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/payment-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/payment-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays payments (Windows `a29ce8d` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `paymentReference`, `date`, `account`, `payee`, `amount` · **Optional:** `voucherNumber` (required when `paymentReference` is longer than 25 characters), `voucherSeries`, `allocations`, `instrumentNumber`, `shortNarration`, `narration` · operation `busy.payments.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY payment – create*, called through the Cloud Relay with the same organization token that reads. **An accounting entry only: AI Zeny never pays, transfers or issues anything.** One cash-in-hand, bank or bank OD `account` pays (is credited) `amount` to one `payee` (debited); a cash ↔ bank transfer is a contra, not a payment (`422 PAYMENT_ACCOUNT_UNSUPPORTED`). SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Negative balances (owner decision PY-10):** a payment is **never refused for an insufficient balance** — it may leave Cash, Bank or Bank OD negative — and `data.accountBalanceAfter { asOfDate, balance, side }` returns the paying account's balance at the end of the payment date (this payment included; later-dated vouchers not). Positive = funds held (`debit`), negative = overdrawn (`credit`).\n\n**Identities:** `paymentReference` (yours, 1-60, unique among the company's payments of the year → `409 PAYMENT_REFERENCE_TAKEN` + `details.paymentId`); `voucherNumber` (1-25, default `paymentReference` when it fits 25 characters; new in a **manually** numbered series → `409 PAYMENT_NUMBER_TAKEN`; automatic series `422 PAYMENT_SERIES_UNSUPPORTED`; `metadata.voucherNumberSource` says which).\n\n**Allocations** (optional, 1-100, only for a payee BUSY keeps bill by bill, else `422 PAYMENT_ALLOCATION_UNSUPPORTED`): each `{ \"bill\": { \"number\" } }` (one of the payee's own outstanding bills; never over-settled → `422 PAYMENT_BILL_NOT_FOUND` / `PAYMENT_BILL_OVERSETTLED`) or `{ \"newReference\": { \"number\", \"dueDate\" } }` (an advance under a number new to the payee → else `409 PAYMENT_NEW_REFERENCE_TAKEN`; `dueDate` on or after `date`, ≤ 5 years, default `date`), with an `amount` > 0 (2 decimals); each number once; together **at most** `amount` (the rest stays on account). `amount` > 0, ≤ 9999999999.99, 2 decimals. `instrumentNumber` 1-30 is a record only. Body ≤ **64 KiB**.\n\n**Idempotency-Key lifecycle (Postman):** minted only when none is held, **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, cleared after a definite answer; never a fresh `eb4acb25-242d-49c6-837d-d7c938363937` per send.\n\n**Uncertain writes:** after `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` look the payment up by `paymentReference`; to recover deliberately unset `cloudIdempotencyKey` and resend the same body: if the first one saved, the answer is `409 PAYMENT_REFERENCE_TAKEN` with `details.paymentId`. `502 BUSY_WRITE_UNVERIFIED` = saved, read-back differs: check it in BUSY. Only `503 BUSY_COM_QUEUE_TIMEOUT` is retryable.\n\n**Other errors:** `409 PAYMENT_MASTER_CHANGED`, `MASTER_WRITE_PROVIDER_UNSUPPORTED`; `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `BUSY_DATA_INCONSISTENT`; `502 BUSY_WRITE_FAILED`.\n\n**Safe test guidance:** development-test company only, a dedicated test payee and a **new, unique** `paymentReference` of at most 25 characters (current value). A created payment stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000109","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"paymentId\": 8930,\n    \"voucherNumber\": \"PV-40211\",\n    \"paymentReference\": \"ERP-PAY-40211\",\n    \"date\": \"2026-10-15\",\n    \"voucherSeries\": { \"code\": 268, \"name\": \"Main\" },\n    \"account\": { \"code\": 9001, \"name\": \"Synthetic Bank\" },\n    \"payee\": { \"code\": 7101, \"name\": \"Synthetic Supplies\" },\n    \"amount\": 2000,\n    \"allocations\": [\n      { \"type\": \"bill\", \"number\": \"SUP-1180\", \"amount\": 1180, \"dueDate\": \"2026-10-30\", \"outstandingBefore\": 1180, \"outstandingAfter\": 0 },\n      { \"type\": \"bill\", \"number\": \"SUP-1205\", \"amount\": 500, \"dueDate\": \"2026-11-04\", \"outstandingBefore\": 1205, \"outstandingAfter\": 705 },\n      { \"type\": \"newReference\", \"number\": \"ADV-40211\", \"amount\": 250, \"dueDate\": \"2026-11-30\", \"outstandingBefore\": null, \"outstandingAfter\": null }\n    ],\n    \"allocatedAmount\": 1930,\n    \"unallocatedAmount\": 70,\n    \"instrumentNumber\": \"SYNCHQ000451\",\n    \"shortNarration\": \"Synthetic cheque\",\n    \"narration\": \"Synthetic supplier payment\",\n    \"ledger\": [\n      { \"account\": { \"code\": 7101, \"name\": \"Synthetic Supplies\" }, \"debit\": 2000, \"credit\": 0 },\n      { \"account\": { \"code\": 9001, \"name\": \"Synthetic Bank\" }, \"debit\": 0, \"credit\": 2000 }\n    ],\n    \"accountBalanceAfter\": { \"asOfDate\": \"2026-10-15\", \"balance\": -350.75, \"side\": \"credit\" }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.payments.create\",\n    \"requestId\": \"rq_0SYNTHET1C0000000000000109\",\n    \"companyCode\": \"COMP0002\",\n    \"financialYear\": \"2026\",\n    \"outcome\": \"created\",\n    \"voucherNumberSource\": \"sent\",\n    \"allocationCount\": 3,\n    \"verification\": [\"busyReadBack\", \"savedRows\", \"settledBills\"],\n    \"elapsedMs\": 2280,\n    \"executedAt\": \"2026-10-15T10:30:00+00:00\"\n  }\n}"},{"id":"17e60a39-b4ad-9948-08c1-32519db0747b","name":"409 – PAYMENT_REFERENCE_TAKEN: a resend after a saved payment (details.paymentId) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held."}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"payee\": { \"name\": \"AZPM-PAY PAYEE\" },\n  \"amount\": 10,\n  \"allocations\": [\n    { \"newReference\": { \"number\": \"{{paymentReference}}\" }, \"amount\": 10 }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/payment-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/payment-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays payments (Windows `a29ce8d` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `paymentReference`, `date`, `account`, `payee`, `amount` · **Optional:** `voucherNumber` (required when `paymentReference` is longer than 25 characters), `voucherSeries`, `allocations`, `instrumentNumber`, `shortNarration`, `narration` · operation `busy.payments.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY payment – create*, called through the Cloud Relay with the same organization token that reads. **An accounting entry only: AI Zeny never pays, transfers or issues anything.** One cash-in-hand, bank or bank OD `account` pays (is credited) `amount` to one `payee` (debited); a cash ↔ bank transfer is a contra, not a payment (`422 PAYMENT_ACCOUNT_UNSUPPORTED`). SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Negative balances (owner decision PY-10):** a payment is **never refused for an insufficient balance** — it may leave Cash, Bank or Bank OD negative — and `data.accountBalanceAfter { asOfDate, balance, side }` returns the paying account's balance at the end of the payment date (this payment included; later-dated vouchers not). Positive = funds held (`debit`), negative = overdrawn (`credit`).\n\n**Identities:** `paymentReference` (yours, 1-60, unique among the company's payments of the year → `409 PAYMENT_REFERENCE_TAKEN` + `details.paymentId`); `voucherNumber` (1-25, default `paymentReference` when it fits 25 characters; new in a **manually** numbered series → `409 PAYMENT_NUMBER_TAKEN`; automatic series `422 PAYMENT_SERIES_UNSUPPORTED`; `metadata.voucherNumberSource` says which).\n\n**Allocations** (optional, 1-100, only for a payee BUSY keeps bill by bill, else `422 PAYMENT_ALLOCATION_UNSUPPORTED`): each `{ \"bill\": { \"number\" } }` (one of the payee's own outstanding bills; never over-settled → `422 PAYMENT_BILL_NOT_FOUND` / `PAYMENT_BILL_OVERSETTLED`) or `{ \"newReference\": { \"number\", \"dueDate\" } }` (an advance under a number new to the payee → else `409 PAYMENT_NEW_REFERENCE_TAKEN`; `dueDate` on or after `date`, ≤ 5 years, default `date`), with an `amount` > 0 (2 decimals); each number once; together **at most** `amount` (the rest stays on account). `amount` > 0, ≤ 9999999999.99, 2 decimals. `instrumentNumber` 1-30 is a record only. Body ≤ **64 KiB**.\n\n**Idempotency-Key lifecycle (Postman):** minted only when none is held, **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, cleared after a definite answer; never a fresh `1ba64a4c-a913-4421-911f-7cf5d8e358ef` per send.\n\n**Uncertain writes:** after `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` look the payment up by `paymentReference`; to recover deliberately unset `cloudIdempotencyKey` and resend the same body: if the first one saved, the answer is `409 PAYMENT_REFERENCE_TAKEN` with `details.paymentId`. `502 BUSY_WRITE_UNVERIFIED` = saved, read-back differs: check it in BUSY. Only `503 BUSY_COM_QUEUE_TIMEOUT` is retryable.\n\n**Other errors:** `409 PAYMENT_MASTER_CHANGED`, `MASTER_WRITE_PROVIDER_UNSUPPORTED`; `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `BUSY_DATA_INCONSISTENT`; `502 BUSY_WRITE_FAILED`.\n\n**Safe test guidance:** development-test company only, a dedicated test payee and a **new, unique** `paymentReference` of at most 25 characters (current value). A created payment stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000110","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PAYMENT_REFERENCE_TAKEN\",\n      \"message\": \"A payment of this company and financial year already holds this paymentReference. A create never changes an existing payment; if your earlier call saved it, metadata.error.details.paymentId names it.\",\n      \"field\": \"paymentReference\",\n      \"details\": { \"paymentId\": 8930 }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000110\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"4b6a2914-8af5-ddcc-969e-8cc8b2c809fc","name":"422 – PAYMENT_BILL_NOT_FOUND: not a bill the payee is owed [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held."}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"payee\": { \"name\": \"AZPM-PAY PAYEE\" },\n  \"amount\": 10,\n  \"allocations\": [\n    { \"newReference\": { \"number\": \"{{paymentReference}}\" }, \"amount\": 10 }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/payment-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/payment-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays payments (Windows `a29ce8d` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `paymentReference`, `date`, `account`, `payee`, `amount` · **Optional:** `voucherNumber` (required when `paymentReference` is longer than 25 characters), `voucherSeries`, `allocations`, `instrumentNumber`, `shortNarration`, `narration` · operation `busy.payments.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY payment – create*, called through the Cloud Relay with the same organization token that reads. **An accounting entry only: AI Zeny never pays, transfers or issues anything.** One cash-in-hand, bank or bank OD `account` pays (is credited) `amount` to one `payee` (debited); a cash ↔ bank transfer is a contra, not a payment (`422 PAYMENT_ACCOUNT_UNSUPPORTED`). SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Negative balances (owner decision PY-10):** a payment is **never refused for an insufficient balance** — it may leave Cash, Bank or Bank OD negative — and `data.accountBalanceAfter { asOfDate, balance, side }` returns the paying account's balance at the end of the payment date (this payment included; later-dated vouchers not). Positive = funds held (`debit`), negative = overdrawn (`credit`).\n\n**Identities:** `paymentReference` (yours, 1-60, unique among the company's payments of the year → `409 PAYMENT_REFERENCE_TAKEN` + `details.paymentId`); `voucherNumber` (1-25, default `paymentReference` when it fits 25 characters; new in a **manually** numbered series → `409 PAYMENT_NUMBER_TAKEN`; automatic series `422 PAYMENT_SERIES_UNSUPPORTED`; `metadata.voucherNumberSource` says which).\n\n**Allocations** (optional, 1-100, only for a payee BUSY keeps bill by bill, else `422 PAYMENT_ALLOCATION_UNSUPPORTED`): each `{ \"bill\": { \"number\" } }` (one of the payee's own outstanding bills; never over-settled → `422 PAYMENT_BILL_NOT_FOUND` / `PAYMENT_BILL_OVERSETTLED`) or `{ \"newReference\": { \"number\", \"dueDate\" } }` (an advance under a number new to the payee → else `409 PAYMENT_NEW_REFERENCE_TAKEN`; `dueDate` on or after `date`, ≤ 5 years, default `date`), with an `amount` > 0 (2 decimals); each number once; together **at most** `amount` (the rest stays on account). `amount` > 0, ≤ 9999999999.99, 2 decimals. `instrumentNumber` 1-30 is a record only. Body ≤ **64 KiB**.\n\n**Idempotency-Key lifecycle (Postman):** minted only when none is held, **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, cleared after a definite answer; never a fresh `b45c0b10-4578-4053-b622-7334e8da9522` per send.\n\n**Uncertain writes:** after `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` look the payment up by `paymentReference`; to recover deliberately unset `cloudIdempotencyKey` and resend the same body: if the first one saved, the answer is `409 PAYMENT_REFERENCE_TAKEN` with `details.paymentId`. `502 BUSY_WRITE_UNVERIFIED` = saved, read-back differs: check it in BUSY. Only `503 BUSY_COM_QUEUE_TIMEOUT` is retryable.\n\n**Other errors:** `409 PAYMENT_MASTER_CHANGED`, `MASTER_WRITE_PROVIDER_UNSUPPORTED`; `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `BUSY_DATA_INCONSISTENT`; `502 BUSY_WRITE_FAILED`.\n\n**Safe test guidance:** development-test company only, a dedicated test payee and a **new, unique** `paymentReference` of at most 25 characters (current value). A created payment stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000111","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"PAYMENT_BILL_NOT_FOUND\",\n      \"message\": \"This number is not an outstanding bill of the payee in BUSY (a bill the payee is still owed). Check the bill's number, or send the amount as a new reference or leave it on account.\",\n      \"field\": \"allocations[0].bill.number\"\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000111\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"5d9a13b6-f59a-fc17-8ecf-213a0c2eb6dc","name":"400 – allocations add up to more than amount (refused by the cloud, nothing sent) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held."}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"payee\": { \"name\": \"AZPM-PAY PAYEE\" },\n  \"amount\": 10,\n  \"allocations\": [\n    { \"newReference\": { \"number\": \"{{paymentReference}}\" }, \"amount\": 10 }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/payment-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/payment-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays payments (Windows `a29ce8d` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `paymentReference`, `date`, `account`, `payee`, `amount` · **Optional:** `voucherNumber` (required when `paymentReference` is longer than 25 characters), `voucherSeries`, `allocations`, `instrumentNumber`, `shortNarration`, `narration` · operation `busy.payments.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY payment – create*, called through the Cloud Relay with the same organization token that reads. **An accounting entry only: AI Zeny never pays, transfers or issues anything.** One cash-in-hand, bank or bank OD `account` pays (is credited) `amount` to one `payee` (debited); a cash ↔ bank transfer is a contra, not a payment (`422 PAYMENT_ACCOUNT_UNSUPPORTED`). SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Negative balances (owner decision PY-10):** a payment is **never refused for an insufficient balance** — it may leave Cash, Bank or Bank OD negative — and `data.accountBalanceAfter { asOfDate, balance, side }` returns the paying account's balance at the end of the payment date (this payment included; later-dated vouchers not). Positive = funds held (`debit`), negative = overdrawn (`credit`).\n\n**Identities:** `paymentReference` (yours, 1-60, unique among the company's payments of the year → `409 PAYMENT_REFERENCE_TAKEN` + `details.paymentId`); `voucherNumber` (1-25, default `paymentReference` when it fits 25 characters; new in a **manually** numbered series → `409 PAYMENT_NUMBER_TAKEN`; automatic series `422 PAYMENT_SERIES_UNSUPPORTED`; `metadata.voucherNumberSource` says which).\n\n**Allocations** (optional, 1-100, only for a payee BUSY keeps bill by bill, else `422 PAYMENT_ALLOCATION_UNSUPPORTED`): each `{ \"bill\": { \"number\" } }` (one of the payee's own outstanding bills; never over-settled → `422 PAYMENT_BILL_NOT_FOUND` / `PAYMENT_BILL_OVERSETTLED`) or `{ \"newReference\": { \"number\", \"dueDate\" } }` (an advance under a number new to the payee → else `409 PAYMENT_NEW_REFERENCE_TAKEN`; `dueDate` on or after `date`, ≤ 5 years, default `date`), with an `amount` > 0 (2 decimals); each number once; together **at most** `amount` (the rest stays on account). `amount` > 0, ≤ 9999999999.99, 2 decimals. `instrumentNumber` 1-30 is a record only. Body ≤ **64 KiB**.\n\n**Idempotency-Key lifecycle (Postman):** minted only when none is held, **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, cleared after a definite answer; never a fresh `679dda98-be67-4570-b9f0-44fdbe3653f0` per send.\n\n**Uncertain writes:** after `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` look the payment up by `paymentReference`; to recover deliberately unset `cloudIdempotencyKey` and resend the same body: if the first one saved, the answer is `409 PAYMENT_REFERENCE_TAKEN` with `details.paymentId`. `502 BUSY_WRITE_UNVERIFIED` = saved, read-back differs: check it in BUSY. Only `503 BUSY_COM_QUEUE_TIMEOUT` is retryable.\n\n**Other errors:** `409 PAYMENT_MASTER_CHANGED`, `MASTER_WRITE_PROVIDER_UNSUPPORTED`; `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `BUSY_DATA_INCONSISTENT`; `502 BUSY_WRITE_FAILED`.\n\n**Safe test guidance:** development-test company only, a dedicated test payee and a **new, unique** `paymentReference` of at most 25 characters (current value). A created payment stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"The allocations add up to more than amount. Allocate at most the amount paid; the rest stays on account.\",\n      \"field\": \"allocations\"\n    },\n    \"requestId\": \"00000000-5e5e-4000-8000-000000000105\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"aa0ecf8a-2ad2-d259-4475-696b46923cfd","name":"504 – WRITE_RESULT_UNKNOWN: the PC's answer was lost (key kept; look up by paymentReference) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held."}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"payee\": { \"name\": \"AZPM-PAY PAYEE\" },\n  \"amount\": 10,\n  \"allocations\": [\n    { \"newReference\": { \"number\": \"{{paymentReference}}\" }, \"amount\": 10 }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/payment-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/payment-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays payments (Windows `a29ce8d` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `paymentReference`, `date`, `account`, `payee`, `amount` · **Optional:** `voucherNumber` (required when `paymentReference` is longer than 25 characters), `voucherSeries`, `allocations`, `instrumentNumber`, `shortNarration`, `narration` · operation `busy.payments.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY payment – create*, called through the Cloud Relay with the same organization token that reads. **An accounting entry only: AI Zeny never pays, transfers or issues anything.** One cash-in-hand, bank or bank OD `account` pays (is credited) `amount` to one `payee` (debited); a cash ↔ bank transfer is a contra, not a payment (`422 PAYMENT_ACCOUNT_UNSUPPORTED`). SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Negative balances (owner decision PY-10):** a payment is **never refused for an insufficient balance** — it may leave Cash, Bank or Bank OD negative — and `data.accountBalanceAfter { asOfDate, balance, side }` returns the paying account's balance at the end of the payment date (this payment included; later-dated vouchers not). Positive = funds held (`debit`), negative = overdrawn (`credit`).\n\n**Identities:** `paymentReference` (yours, 1-60, unique among the company's payments of the year → `409 PAYMENT_REFERENCE_TAKEN` + `details.paymentId`); `voucherNumber` (1-25, default `paymentReference` when it fits 25 characters; new in a **manually** numbered series → `409 PAYMENT_NUMBER_TAKEN`; automatic series `422 PAYMENT_SERIES_UNSUPPORTED`; `metadata.voucherNumberSource` says which).\n\n**Allocations** (optional, 1-100, only for a payee BUSY keeps bill by bill, else `422 PAYMENT_ALLOCATION_UNSUPPORTED`): each `{ \"bill\": { \"number\" } }` (one of the payee's own outstanding bills; never over-settled → `422 PAYMENT_BILL_NOT_FOUND` / `PAYMENT_BILL_OVERSETTLED`) or `{ \"newReference\": { \"number\", \"dueDate\" } }` (an advance under a number new to the payee → else `409 PAYMENT_NEW_REFERENCE_TAKEN`; `dueDate` on or after `date`, ≤ 5 years, default `date`), with an `amount` > 0 (2 decimals); each number once; together **at most** `amount` (the rest stays on account). `amount` > 0, ≤ 9999999999.99, 2 decimals. `instrumentNumber` 1-30 is a record only. Body ≤ **64 KiB**.\n\n**Idempotency-Key lifecycle (Postman):** minted only when none is held, **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, cleared after a definite answer; never a fresh `002aa22b-47d7-48c4-944b-f2bedd95fd95` per send.\n\n**Uncertain writes:** after `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` look the payment up by `paymentReference`; to recover deliberately unset `cloudIdempotencyKey` and resend the same body: if the first one saved, the answer is `409 PAYMENT_REFERENCE_TAKEN` with `details.paymentId`. `502 BUSY_WRITE_UNVERIFIED` = saved, read-back differs: check it in BUSY. Only `503 BUSY_COM_QUEUE_TIMEOUT` is retryable.\n\n**Other errors:** `409 PAYMENT_MASTER_CHANGED`, `MASTER_WRITE_PROVIDER_UNSUPPORTED`; `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `BUSY_DATA_INCONSISTENT`; `502 BUSY_WRITE_FAILED`.\n\n**Safe test guidance:** development-test company only, a dedicated test payee and a **new, unique** `paymentReference` of at most 25 characters (current value). A created payment stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000115"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"WRITE_RESULT_UNKNOWN\",\n      \"message\": \"The PC's answer to this payment did not reach AI Zeny, so whether BUSY saved it is not known. Look the payment up by its paymentReference before trying again; a retry with the same paymentReference is refused if the first one saved (409 PAYMENT_REFERENCE_TAKEN with details.paymentId).\",\n      \"details\": { \"reconciliation\": \"notChecked\" }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000115\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"01514b38-ea74-61c9-f368-95298349d2d5","name":"504 – BUSY_WRITE_UNCERTAIN, reconciled found (details.paymentId; never resend) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"Kept after an uncertain outcome; minted by the pre-request script only when none is held."}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"paymentReference\": \"{{paymentReference}}\",\n  \"date\": \"2026-10-15\",\n  \"voucherSeries\": { \"name\": \"Main\" },\n  \"account\": { \"name\": \"Cash\" },\n  \"payee\": { \"name\": \"AZPM-PAY PAYEE\" },\n  \"amount\": 10,\n  \"allocations\": [\n    { \"newReference\": { \"number\": \"{{paymentReference}}\" }, \"amount\": 10 }\n  ],\n  \"shortNarration\": \"Postman test payment\",\n  \"narration\": \"Postman test payment (accounting entry only)\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/payment-create","description":"**Cloud** · `POST {{cloudBaseUrl}}/v1/payment-create` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · **⚠ Writes to BUSY** (guarded: needs `confirmMutating` = `yes`; sends an `Idempotency-Key`)\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version that relays payments (Windows `a29ce8d` or later — **not** in public release 0.0.12); an earlier version answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`) and writes nothing.\n**Required:** `companyCode`, `financialYear`, `paymentReference`, `date`, `account`, `payee`, `amount` · **Optional:** `voucherNumber` (required when `paymentReference` is longer than 25 characters), `voucherSeries`, `allocations`, `instrumentNumber`, `shortNarration`, `narration` · operation `busy.payments.create`\n**Answer:** `{ success, data, metadata }` as the Local API answers it (errors: `success: false`, `data: null`, `metadata.error`).\n\n---\n\n**Mutating — writes to the BUSY books on the organization's PC (it must be online). Run manually, one at a time; never in a collection run.** Same operation, body and answer as the Local request *Local PC → ⚠ Voucher Create → ⚠ BUSY payment – create*, called through the Cloud Relay with the same organization token that reads. **An accounting entry only: AI Zeny never pays, transfers or issues anything.** One cash-in-hand, bank or bank OD `account` pays (is credited) `amount` to one `payee` (debited); a cash ↔ bank transfer is a contra, not a payment (`422 PAYMENT_ACCOUNT_UNSUPPORTED`). SQL Server companies with a SQL login, and Access companies (Windows `6c5776d` or later; an earlier PC answers Access with `409 MASTER_WRITE_PROVIDER_UNSUPPORTED`).\n\n**Negative balances (owner decision PY-10):** a payment is **never refused for an insufficient balance** — it may leave Cash, Bank or Bank OD negative — and `data.accountBalanceAfter { asOfDate, balance, side }` returns the paying account's balance at the end of the payment date (this payment included; later-dated vouchers not). Positive = funds held (`debit`), negative = overdrawn (`credit`).\n\n**Identities:** `paymentReference` (yours, 1-60, unique among the company's payments of the year → `409 PAYMENT_REFERENCE_TAKEN` + `details.paymentId`); `voucherNumber` (1-25, default `paymentReference` when it fits 25 characters; new in a **manually** numbered series → `409 PAYMENT_NUMBER_TAKEN`; automatic series `422 PAYMENT_SERIES_UNSUPPORTED`; `metadata.voucherNumberSource` says which).\n\n**Allocations** (optional, 1-100, only for a payee BUSY keeps bill by bill, else `422 PAYMENT_ALLOCATION_UNSUPPORTED`): each `{ \"bill\": { \"number\" } }` (one of the payee's own outstanding bills; never over-settled → `422 PAYMENT_BILL_NOT_FOUND` / `PAYMENT_BILL_OVERSETTLED`) or `{ \"newReference\": { \"number\", \"dueDate\" } }` (an advance under a number new to the payee → else `409 PAYMENT_NEW_REFERENCE_TAKEN`; `dueDate` on or after `date`, ≤ 5 years, default `date`), with an `amount` > 0 (2 decimals); each number once; together **at most** `amount` (the rest stays on account). `amount` > 0, ≤ 9999999999.99, 2 decimals. `instrumentNumber` 1-30 is a record only. Body ≤ **64 KiB**.\n\n**Idempotency-Key lifecycle (Postman):** minted only when none is held, **kept** after any `504` or `409 REQUEST_IN_PROGRESS` / `IDEMPOTENT_REPLAY_UNAVAILABLE` / `IDEMPOTENCY_KEY_REUSED`, cleared after a definite answer; never a fresh `3fe71b86-c0ff-4fc0-bf57-67a3496249ed` per send.\n\n**Uncertain writes:** after `504 WRITE_RESULT_UNKNOWN` or `504 BUSY_WRITE_UNCERTAIN` look the payment up by `paymentReference`; to recover deliberately unset `cloudIdempotencyKey` and resend the same body: if the first one saved, the answer is `409 PAYMENT_REFERENCE_TAKEN` with `details.paymentId`. `502 BUSY_WRITE_UNVERIFIED` = saved, read-back differs: check it in BUSY. Only `503 BUSY_COM_QUEUE_TIMEOUT` is retryable.\n\n**Other errors:** `409 PAYMENT_MASTER_CHANGED`, `MASTER_WRITE_PROVIDER_UNSUPPORTED`; `422 MASTER_REFERENCE_NOT_FOUND` / `_AMBIGUOUS`, `BUSY_DATA_INCONSISTENT`; `502 BUSY_WRITE_FAILED`.\n\n**Safe test guidance:** development-test company only, a dedicated test payee and a **new, unique** `paymentReference` of at most 25 characters (current value). A created payment stays in BUSY. Saved examples are synthetic.\n\n**Durable queue:** optional strict `queue` (omitted or `false`: synchronous; `true`: a `202` job acknowledgement, not a saved record). There are no Cloud job-polling or company-webhook management routes. Preserve the Cloud-signed company/FY/operation/request ID; do not substitute an unsigned ID.\n\n\n---\n\n**Parity update (2026-10-23, deployed in release `790395a`; the PC must be Windows `6c5776d` or later for these members).** This request's body sends only the basic members. New optional members and codes:\n\n- `queue` (optional, `true` or `false`, default `false`; `null` is refused `400`): with `true` the PC accepts the write on its durable queue and the answer is **`202`** with `data: null` and `metadata.queued: true`, `metadata.jobId` (32 hex), `metadata.status` — acceptance, **not** a saved voucher; the job id is never a voucher or master id, and the result stays on the PC (and may reach the company's webhook). As on the PC, a queued body is checked only for its shape and a signable `companyCode`/four-digit `financialYear`; the write's own rules run on the PC when the job executes, so a body they refuse is still accepted (`202`) and fails there. The cloud sends it once.\n- Shared refusals of every write, answered before anything is written: `403 PLAN_FEATURE_NOT_INCLUDED`, `409 PLAN_NOT_KNOWN`, `503 BUSY_COM_RECOVERY_REQUIRED`, `409 BUSY_WRITE_TARGET_CHANGED`, `422 BUSY_SETTING_REQUIRED`, `502 BUSY_SETTINGS_UNREADABLE`; queue refusals `409 WRITE_QUEUE_REQUEST_CONFLICT`, `503 WRITE_QUEUE_UNAVAILABLE`.\n\nScenario requests for the new members are in this folder, named `⚠ Scenario – …` and `⚠ EXPECTED REFUSAL …`; they are guarded like this one (`confirmMutating` = `yes`, one send). Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md."},"status":"Gateway Timeout","code":504,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000112"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_WRITE_UNCERTAIN\",\n      \"message\": \"BUSY stopped while saving the payment; a payment with this paymentReference exists now (metadata.error.details.paymentId). Check it in BUSY; do not send it again.\",\n      \"details\": { \"paymentId\": 8931, \"reconciliation\": \"found\" }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000112\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"1d1b3508-d669-171d-a8a8-cb3256af44a0"},{"name":"⚠ BUSY stock transfer – create (writes to BUSY)","id":"8d149a3c-87f4-cc1c-464f-778022b61ecb","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"transferReference\": \"{{stockTransferReference}}\",\n  \"date\": \"2026-10-21\",\n  \"sourceMaterialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"destinationMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_DESTINATION_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ]\n}"},"url":"{{cloudBaseUrl}}/v1/stock-transfer-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/stock-transfer-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.stock-transfers.create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Body</strong> (at most 128 KiB; the PC also accepts at most 64 KiB per signed command): companyCode, financialYear, transferReference, date (YYYY-MM-DD), sourceMaterialCenter and destinationMaterialCenter ({code} or {name}), lines (1-100: item, quantity, rate; optional listPrice, description), optional voucherSeries, documentNumber, documentDate, narration, queue. Optional queue (boolean, default false).</p>\n<p><strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it. <strong>200</strong> <code>data</code> = { transferId (BUSY's voucher code), transferNumber, transferReference, date, voucherSeries, sourceMaterialCenter, destinationMaterialCenter (each { code, name }), lines: [ { lineNumber, item, unit, alternateUnit, conversionFactor, quantity, alternateQuantity, rate, alternateRate, listPrice, amount, description [] } ], totalTransferValue, documentNumber, documentDate, narration } — every value as BUSY stored it; both legs (issue and receipt) are one voucher. <code>metadata</code> = apiVersion, operation, requestId, companyCode, financialYear, outcome (\"created\"), lineCount, verification ([\"busyReadBack\", \"savedRows\"]), elapsedMs, executedAt.</p>\n<p><strong>Before sending:</strong> set <code>stockTransferReference</code> (current values; the request is skipped until they are set), replace every <code>REPLACE_WITH_…</code> value with an existing master of the test company (skipped until you do), set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Look the transfer up in BUSY by transferReference; to recover deliberately, unset cloudIdempotencyKey and resend the SAME body: a saved first send answers 409 STOCK_TRANSFER_REFERENCE_TAKEN with details.transferId. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p><strong>Route errors:</strong> 400 INVALID_PARAMETER field transferReference, narration, documentNumber, date, documentDate, voucherSeries / sourceMaterialCenter / destinationMaterialCenter (and .code / .name), lines (also \"Each amount and the total transfer value must be at most 9999999999.99.\"), lines[i], lines[i].item, lines[i].quantity, lines[i].rate, lines[i].listPrice, lines[i].description; from the PC also the masters and settings it resolves. Plus the shared write refusals (plan, BUSY COM, changed destination, settings, queue) in the operations reference.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Cloud Relay has not deployed the new numbering schema; these are documentation examples only. Do not Send until Cloud parity is deployed and verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"transferReference\": \"{{stockTransferReference}}\",\n  \"date\": \"2026-10-21\",\n  \"sourceMaterialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"destinationMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_DESTINATION_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\",\n  \"voucherSeries\": {\n    \"code\": 101\n  }\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"transferReference\": \"{{stockTransferReference}}\",\n  \"date\": \"2026-10-21\",\n  \"sourceMaterialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"destinationMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_DESTINATION_CENTRE\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"numberingMode\": \"auto\",\n  \"voucherSeries\": {\n    \"code\": 102\n  }\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","urlObject":{"path":["v1","stock-transfer-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"8d149a3c-87f4-cc1c-464f-778022b61ecb"},{"name":"⚠ BUSY purchase order – create (writes to BUSY)","id":"f889115e-4ded-4bc5-a329-62a665124a70","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{purchaseOrderReference}}\",\n  \"date\": \"2026-10-21\",\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100,\n      \"description\": [\n        \"Postman cloud test purchase order\"\n      ]\n    }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-order-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/purchase-order-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.purchase-orders.create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Body</strong> (at most 128 KiB; the PC also accepts at most 64 KiB per signed command): companyCode, financialYear, orderReference, date, supplier, purchaseType, materialCenter, lines; optional voucherSeries, billSundries, dueDate, documentNumber, documentDate, narration, taxCalculation, pricingMode, totals, queue. Optional queue (boolean, default false).</p>\n<p><strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it. <strong>200</strong> <code>data</code> = { orderId (BUSY's voucher code), orderNumber, orderReference, date, voucherSeries, supplier, purchaseType, materialCenter (each { code, name }), taxCalculation, pricingMode, lines: [ { lineNumber, item, unit, quantity, rate, netRate, discountPercent, mrp, description [], taxableAmount, cgst, sgst, igst, amount, discountShare, pendingReferenceCode, pendingReferenceNumber, pendingQuantity, pendingRate, dueDate } ], billSundries: [ { lineNumber, billSundry, kind, percent, baseAmount, amount, effect } ], taxableAmount, cgst, sgst, igst, linesAmount, totalAmount, documentNumber, documentDate, narration } — every value as BUSY stored it. <code>metadata</code> = apiVersion, operation, requestId, companyCode, financialYear, outcome (\"created\"), lineCount, verification ([\"busyReadBack\", \"savedRows\"]), elapsedMs, executedAt.</p>\n<p><strong>Before sending:</strong> set <code>purchaseOrderReference</code> (current values; the request is skipped until they are set), set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY. On success the test stores <code>purchaseOrderId</code>.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Look the order up in BUSY by orderReference; to recover deliberately, unset cloudIdempotencyKey and resend the SAME body: a saved first send answers 409 PURCHASE_ORDER_REFERENCE_TAKEN with details.orderId. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p><strong>Route errors:</strong> 400 INVALID_PARAMETER field orderReference, narration, documentNumber, date, dueDate, documentDate, voucherSeries / supplier / purchaseType / materialCenter (and .code / .name), lines, lines[i] (also \"The order amount exceeds the supported limit.\" on lines), lines[i].quantity, lines[i].rate, lines[i].discountPercent, lines[i].mrp, lines[i].description, lines[i].dueDate, lines[i].amounts, totals, taxCalculation, pricingMode, billSundries[i]; from the PC also voucherSeries (one automatic Purchase Order series), supplier, purchaseType, lines[i].item (serial, batch or parameter items; units; GST category), lines[i].quantity (BUSY's precision), lines[i].description (the series' description positions); 502 BUSY_WRITE_UNVERIFIED (BUSY may have saved, but verification failed: details.orderId, details.mismatchedFields; never resend). Plus the shared write refusals (plan, BUSY COM, changed destination, settings, queue) in the operations reference.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Cloud Relay has not deployed the new numbering schema; these are documentation examples only. Do not Send until Cloud parity is deployed and verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{purchaseOrderReference}}\",\n  \"date\": \"2026-10-21\",\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100,\n      \"description\": [\n        \"Postman cloud test purchase order\"\n      ]\n    }\n  ],\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\",\n  \"voucherSeries\": {\n    \"code\": 101\n  }\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{purchaseOrderReference}}\",\n  \"date\": \"2026-10-21\",\n  \"supplier\": {\n    \"name\": \"AZPOC-PUR SUPP MP\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100,\n      \"description\": [\n        \"Postman cloud test purchase order\"\n      ]\n    }\n  ],\n  \"numberingMode\": \"auto\",\n  \"voucherSeries\": {\n    \"code\": 102\n  }\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","urlObject":{"path":["v1","purchase-order-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"f889115e-4ded-4bc5-a329-62a665124a70"},{"name":"⚠ BUSY material issue – create (writes to BUSY)","id":"4e3c9d51-567a-8983-c214-1789be27cc6b","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n","key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialIssueReference}}\",\n  \"date\": \"2026-10-22\",\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/material-issue-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/material-issue-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.material-issues.create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Body</strong> (at most 128 KiB; the PC also accepts at most 64 KiB per signed command): companyCode, financialYear, materialReference, date, party and materialCenter ({code} or {name}), lines (1-100: item, quantity, rate; optional listPrice, mrp, description); optional voucherSeries, salesman (Receipt only), transport, grNumber, grDate, vehicleNumber, station, narration, queue. Optional queue (boolean, default false).</p>\n<p><strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it. <strong>200</strong> <code>data</code> = { voucherId (BUSY's voucher code), voucherNumber, voucherType (11), materialReference, date, voucherSeries, party, materialCenter (each { code, name }), salesman ({ code, name } or null), billing { name, address1-address4, mobile, email, panNumber, gstNumber, dealerType, source }, lines: [ { lineNumber, item, unit, alternateUnit, conversionFactor, quantity, alternateQuantity, rate, alternateRate, listPrice, mrp, amount, description [] } ], totalMaterialValue, transport, grNumber, grDate, vehicleNumber, station, narration } — every value as BUSY stored it. <code>metadata</code> = apiVersion, operation, requestId, companyCode, financialYear, outcome (\"created\"), lineCount, verification ([\"busyReadBack\", \"savedRows\"]), elapsedMs, executedAt.</p>\n<p><strong>Before sending:</strong> set <code>materialIssueReference</code> (current values; the request is skipped until they are set), replace every <code>REPLACE_WITH_…</code> value with an existing master of the test company (skipped until you do), set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Look the voucher up in BUSY by materialReference; to recover deliberately, unset cloudIdempotencyKey and resend the SAME body: a saved first send answers 409 MATERIAL_PARTY_REFERENCE_TAKEN with details.voucherId. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p><strong>Route errors:</strong> 400 INVALID_PARAMETER field materialReference, narration, transport, grNumber, vehicleNumber, station, date, grDate, salesman (an issue takes no salesman), voucherSeries / party / materialCenter / salesman (and .code / .name), lines, lines[i], lines[i].item, lines[i].quantity, lines[i].rate (also listPrice and mrp), lines[i].description; from the PC also the masters and settings it resolves. Plus the shared write refusals (plan, BUSY COM, changed destination, settings, queue) in the operations reference.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Cloud Relay has not deployed the new numbering schema; these are documentation examples only. Do not Send until Cloud parity is deployed and verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialIssueReference}}\",\n  \"date\": \"2026-10-22\",\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\",\n  \"voucherSeries\": {\n    \"code\": 101\n  }\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialIssueReference}}\",\n  \"date\": \"2026-10-22\",\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"numberingMode\": \"auto\",\n  \"voucherSeries\": {\n    \"code\": 102\n  }\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","urlObject":{"path":["v1","material-issue-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"4e3c9d51-567a-8983-c214-1789be27cc6b"},{"name":"⚠ BUSY material receipt – create (writes to BUSY)","id":"29206f81-eeb3-e562-84dd-3216b5208ecd","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"value":"{{cloudIdempotencyKey}}","key":"Idempotency-Key","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialReceiptReference}}\",\n  \"date\": \"2026-10-22\",\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/material-receipt-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/material-receipt-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.material-receipts.create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Body</strong> (at most 128 KiB; the PC also accepts at most 64 KiB per signed command): companyCode, financialYear, materialReference, date, party and materialCenter ({code} or {name}), lines (1-100: item, quantity, rate; optional listPrice, mrp, description); optional voucherSeries, salesman (Receipt only), transport, grNumber, grDate, vehicleNumber, station, narration, queue. Optional queue (boolean, default false).</p>\n<p><strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it. <strong>200</strong> <code>data</code> = { voucherId (BUSY's voucher code), voucherNumber, voucherType (4), materialReference, date, voucherSeries, party, materialCenter (each { code, name }), salesman ({ code, name } or null), billing { name, address1-address4, mobile, email, panNumber, gstNumber, dealerType, source }, lines: [ { lineNumber, item, unit, alternateUnit, conversionFactor, quantity, alternateQuantity, rate, alternateRate, listPrice, mrp, amount, description [] } ], totalMaterialValue, transport, grNumber, grDate, vehicleNumber, station, narration } — every value as BUSY stored it. <code>metadata</code> = apiVersion, operation, requestId, companyCode, financialYear, outcome (\"created\"), lineCount, verification ([\"busyReadBack\", \"savedRows\"]), elapsedMs, executedAt.</p>\n<p><strong>Before sending:</strong> set <code>materialReceiptReference</code> (current values; the request is skipped until they are set), replace every <code>REPLACE_WITH_…</code> value with an existing master of the test company (skipped until you do), set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Look the voucher up in BUSY by materialReference; to recover deliberately, unset cloudIdempotencyKey and resend the SAME body: a saved first send answers 409 MATERIAL_PARTY_REFERENCE_TAKEN with details.voucherId. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p><strong>Route errors:</strong> 400 INVALID_PARAMETER field materialReference, narration, transport, grNumber, vehicleNumber, station, date, grDate, voucherSeries / party / materialCenter / salesman (and .code / .name), lines, lines[i], lines[i].item, lines[i].quantity, lines[i].rate (also listPrice and mrp), lines[i].description; from the PC also the masters and settings it resolves. Plus the shared write refusals (plan, BUSY COM, changed destination, settings, queue) in the operations reference.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n<h3 id=\"numbering-modes--source-only-examples-30-oct-2026\">Numbering modes — source-only examples (30 Oct 2026)</h3>\n<p><strong>⚠ REAL BUSY WRITE if sent. Cloud Relay has not deployed the new numbering schema; these are documentation examples only. Do not Send until Cloud parity is deployed and verified.</strong> Replace synthetic series codes 101 (manual) and 102 (auto) with real matching series in a disposable test company. Use a fresh reference and reconcile any uncertain outcome; never blindly retry. Existing request body remains the omitted-mode legacy example.</p>\n<p>Manual-number example (full body):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialReceiptReference}}\",\n  \"date\": \"2026-10-22\",\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"numberingMode\": \"manual\",\n  \"voucherNumber\": \"0007-A\",\n  \"voucherSeries\": {\n    \"code\": 101\n  }\n}\n</code></pre>\n<p>Automatic-number example (full body; no <code>voucherNumber</code>):</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-json\">{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"materialReference\": \"{{materialReceiptReference}}\",\n  \"date\": \"2026-10-22\",\n  \"party\": {\n    \"name\": \"REPLACE_WITH_SYNTHETIC_PARTY\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 10\n    }\n  ],\n  \"numberingMode\": \"auto\",\n  \"voucherSeries\": {\n    \"code\": 102\n  }\n}\n</code></pre>\n<p>Static negative cases to check against the contract: invalid mode/case/type, blank or 26-character manual number, explicit auto with <code>voucherNumber</code>, mismatched series, duplicate number, and held/review-required original intent. A queued 202 is acceptance, not a native save. Source contract: <code>docs/features/BUSY-Voucher-Numbering-Modes-API.md</code>.</p>\n","urlObject":{"path":["v1","material-receipt-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"29206f81-eeb3-e562-84dd-3216b5208ecd"},{"name":"⚠ Scenario – sales order with queue: true (202 acceptance, not a saved order)","id":"1a8b00cf-57e4-0d16-8246-d2c77536eb07","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 3,\n      \"rate\": 150,\n      \"description\": [\n        \"Queued synthetic line\"\n      ]\n    }\n  ],\n  \"queue\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-order-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/sales-order-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.sales-orders.create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Scenario.</strong> It queues a real sales order on the PC (the PC saves it when the job runs). Same route, body rules and answers as the main request of this operation in this folder; this body exercises the parity members.</p>\n<p><strong>Before sending:</strong> set <code>salesOrderReference</code> (current values; the request is skipped until they are set), set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Look it up in BUSY first. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","sales-order-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"1a8b00cf-57e4-0d16-8246-d2c77536eb07"},{"name":"⚠ Scenario – sales invoice, Manual GST + salesman + eInvoiceRequired + descriptions (writes to BUSY)","id":"6d643435-80a7-a7b1-23c7-cbed6088ec35","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"invoiceReference\": \"{{salesInvoiceReference}}\",\n  \"date\": \"2026-10-13\",\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstExclusive\",\n  \"eInvoiceRequired\": false,\n  \"salesman\": {\n    \"name\": \"AZPOC SALESMAN 01\"\n  },\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 2,\n      \"rate\": 100.10,\n      \"description\": [\n        \"Line one\",\n        null,\n        \"Line three\"\n      ],\n      \"amounts\": {\n        \"taxableAmount\": 200.20,\n        \"cgst\": 18.02,\n        \"sgst\": 18.02,\n        \"igst\": 0,\n        \"amount\": 236.24\n      }\n    }\n  ],\n  \"totals\": {\n    \"taxableAmount\": 200.20,\n    \"cgst\": 18.02,\n    \"sgst\": 18.02,\n    \"igst\": 0,\n    \"amount\": 236.24\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-invoice-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/sales-invoice-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.sales-invoices.create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Scenario.</strong> It creates a real sales invoice in BUSY with Manual GST, a salesman, the E-Invoice flag and line descriptions. Same route, body rules and answers as the main request of this operation in this folder; this body exercises the parity members.</p>\n<p><strong>Before sending:</strong> set <code>salesInvoiceReference</code> (current values; the request is skipped until they are set), set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Look it up in BUSY first. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","sales-invoice-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"6d643435-80a7-a7b1-23c7-cbed6088ec35"},{"name":"⚠ Scenario – purchase, Manual GST inclusive pricing (writes to BUSY)","id":"c270e08e-8a14-3959-94f2-e6b0fa5fb8cb","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-16\",\n  \"supplierInvoice\": {\n    \"number\": \"{{supplierInvoiceNumber}}\",\n    \"date\": \"2026-10-15\"\n  },\n  \"supplier\": {\n    \"name\": \"Synthetic Supplies\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise-Inclusive\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"taxCalculation\": \"manual\",\n  \"pricingMode\": \"gstInclusive\",\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic Widget\"\n      },\n      \"quantity\": 10,\n      \"rate\": 118,\n      \"description\": [\n        \"Inclusive synthetic line\"\n      ],\n      \"amounts\": {\n        \"taxableAmount\": 1000,\n        \"cgst\": 90,\n        \"sgst\": 90,\n        \"igst\": 0,\n        \"amount\": 1180\n      }\n    }\n  ],\n  \"totals\": {\n    \"taxableAmount\": 1000,\n    \"cgst\": 90,\n    \"sgst\": 90,\n    \"igst\": 0,\n    \"amount\": 1180\n  }\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/purchase-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.purchases.create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Scenario.</strong> It creates a real purchase in BUSY with Manual GST and inclusive pricing. Same route, body rules and answers as the main request of this operation in this folder; this body exercises the parity members.</p>\n<p><strong>Before sending:</strong> set <code>purchaseReference</code>, <code>supplierInvoiceNumber</code> (current values; the request is skipped until they are set), set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Look it up in BUSY first. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","purchase-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"c270e08e-8a14-3959-94f2-e6b0fa5fb8cb"},{"name":"⚠ EXPECTED REFUSAL 400 – sales order Manual GST without totals (cloud refuses, nothing sent)","id":"1b126de8-6342-a221-10e6-b294b86eeaf8","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"orderReference\": \"{{salesOrderReference}}\",\n  \"date\": \"2026-10-13\",\n  \"customer\": {\n    \"name\": \"AZPOC-POSTMAN ACC 01\"\n  },\n  \"saleType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"taxCalculation\": \"manual\",\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"AZPOC-SVC ITEM 01\"\n      },\n      \"quantity\": 1,\n      \"rate\": 100,\n      \"amounts\": {\n        \"taxableAmount\": 100,\n        \"cgst\": 9,\n        \"sgst\": 9,\n        \"igst\": 0,\n        \"amount\": 118\n      }\n    }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/sales-order-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/sales-order-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.sales-orders.create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Scenario.</strong> The cloud must refuse it before anything reaches the PC; the guard stays because the route itself writes. Same route, body rules and answers as the main request of this operation in this folder; this body exercises a refusal.</p>\n<p><strong>Before sending:</strong> set <code>salesOrderReference</code> (current values; the request is skipped until they are set), set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Look it up in BUSY first. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","sales-order-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"1b126de8-6342-a221-10e6-b294b86eeaf8"},{"name":"⚠ EXPECTED REFUSAL 422 – purchase Manual GST with bill sundries (cloud refuses, nothing sent)","id":"01ab892e-aa17-c700-eb14-90b35f36f204","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"{{cloudIdempotencyKey}}","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"purchaseReference\": \"{{purchaseReference}}\",\n  \"date\": \"2026-10-16\",\n  \"supplierInvoice\": {\n    \"number\": \"{{supplierInvoiceNumber}}\",\n    \"date\": \"2026-10-15\"\n  },\n  \"supplier\": {\n    \"name\": \"Synthetic Supplies\"\n  },\n  \"purchaseType\": {\n    \"name\": \"Local-ItemWise\"\n  },\n  \"materialCenter\": {\n    \"name\": \"Main Store\"\n  },\n  \"taxCalculation\": \"manual\",\n  \"lines\": [\n    {\n      \"item\": {\n        \"name\": \"Synthetic Widget\"\n      },\n      \"quantity\": 10,\n      \"rate\": 100,\n      \"amounts\": {\n        \"taxableAmount\": 1000,\n        \"cgst\": 90,\n        \"sgst\": 90,\n        \"igst\": 0,\n        \"amount\": 1180\n      }\n    }\n  ],\n  \"totals\": {\n    \"taxableAmount\": 1000,\n    \"cgst\": 90,\n    \"sgst\": 90,\n    \"igst\": 0,\n    \"amount\": 1180\n  },\n  \"billSundries\": [\n    {\n      \"billSundry\": {\n        \"name\": \"Freight & Forwarding Charges\"\n      },\n      \"amount\": 50\n    }\n  ]\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/purchase-create","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/purchase-create</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.purchases.create</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Scenario.</strong> The cloud must refuse it before anything reaches the PC; the guard stays because the route itself writes. Same route, body rules and answers as the main request of this operation in this folder; this body exercises a refusal.</p>\n<p><strong>Before sending:</strong> set <code>purchaseReference</code>, <code>supplierInvoiceNumber</code> (current values; the request is skipped until they are set), set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Look it up in BUSY first. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","purchase-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"01ab892e-aa17-c700-eb14-90b35f36f204"},{"name":"⏭ CONTRACT POINTER — Stock Journal Cloud Relay (NOT DEPLOYED; always skipped)","id":"94914ae5-cc73-6242-8e07-5ee7f4f93a6d","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"journalReference\": \"REPLACE_WITH_FRESH_SYNTHETIC_REFERENCE\",\n  \"date\": \"2026-10-20\",\n  \"productionMaterialCenter\": {\n    \"name\": \"REPLACE_WITH_PRODUCTION_CENTRE\"\n  },\n  \"productionLines\": [\n    {\n      \"item\": {\n        \"name\": \"REPLACE_WITH_UNTRACKED_ITEM\"\n      },\n      \"quantity\": 1,\n      \"rate\": 1\n    }\n  ],\n  \"queue\": false\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/stock-journal-create","description":"<p>Contract pointer only. The Windows Local route busy.stock-journals.create exists, but the Cloud Relay route/validator/deployed acceptance have not been implemented or proven by this task. This request ALWAYS skips before sending, even if collection confirmation variables are enabled. Do not remove its skip until a separate cloud implementation, deployment and acceptance task updates the cloud contract. No Cloud Snapshot write route exists. See docs/integration/Cloud-Stock-Journal-Relay-Handoff.md. Synthetic placeholder body only; it is not a runnable cloud example.</p>\n","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}},"urlObject":{"path":["v1","stock-journal-create"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"94914ae5-cc73-6242-8e07-5ee7f4f93a6d"}],"id":"05ad8915-0a3f-477d-ba8c-7641e214b9a9","_postman_id":"05ad8915-0a3f-477d-ba8c-7641e214b9a9","description":"","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ Report PDFs — native side effects unverified","item":[{"name":"⚠ busy.reports.account-ledger.pdf – Account Ledger PDF","id":"f7f3ecd0-ee7c-aaea-c10f-6b5233bb8367","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": 7101 },\n  \"fromDate\": \"2026-04-01\",\n  \"toDate\": \"2026-06-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/account-ledger-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /v1/account-ledger-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.</p>\n<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/account-ledger-pdf</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — BUSY prints a report; nothing in BUSY changes\n<strong>Status (2026-10-23):</strong> deployed and live (release <code>790395a</code>). The PC needs an AI Zeny version with the report PDFs (Windows <code>75d5602</code> or later — <strong>not</strong> in public release 0.0.12); an earlier one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>).\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>account</code> · <strong>Optional:</strong> <code>fromDate</code>, <code>toDate</code> · operation <code>busy.reports.account-ledger.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body and answer as the Local request <em>Local PC → Report PDFs → Account Ledger PDF</em>, through the Cloud Relay.</strong> One account's <strong>Account Ledger</strong> (BUSY report 19) printed by BUSY's own report printing on the online PC: the opening balance at <code>fromDate</code>, every entry of the period with its running balance, totals and the closing balance. A document: no <code>Idempotency-Key</code>, no <code>script</code>; a failed or timed-out call may be repeated (it writes nothing).</p>\n<p><strong>Body:</strong> <code>account</code> = exactly one of <code>{ \"code\": n }</code> (1-2147483647) or <code>{ \"name\": \"…\" }</code> (1-60, compared without case and surrounding spaces); an account master only (a group's or item's code is <code>404 NOT_FOUND</code>), refused <code>422 MASTER_REFERENCE_AMBIGUOUS</code> when another account holds its name as a name or alias. <code>fromDate</code> / <code>toDate</code>: exactly <code>YYYY-MM-DD</code>, real dates inside the selected financial year, <code>fromDate</code> ≤ <code>toDate</code> (<code>400 INVALID_PARAMETER</code>, checked in the cloud — BUSY validates none of them); default the whole year. Unknown members (<code>formatName</code>, <code>startDate</code> …) are <code>400 BAD_REQUEST</code>. Body ≤ 16 KiB.</p>\n<p><strong>Answer:</strong> <code>data</code> = <code>{ fileName (AccountLedger-&lt;company&gt;-&lt;year&gt;-&lt;account code&gt;-&lt;from&gt;-&lt;to&gt;.pdf), mimeType, byteLength, sha256, pages, contentBase64 }</code> — decode <code>contentBase64</code> (standard base64, one line); its SHA-256 is <code>sha256</code>. <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, report (\"accountLedger\"), busyReportId (19), account { code, name }, fromDate, toDate, elapsedMs, executedAt</code>.</p>\n<p><strong>⚠ Size limitation:</strong> the PC prints up to 8 MiB, but a relayed answer — base64 and envelope included — is limited to <strong>2 MiB</strong>, so only PDFs up to <strong>about 1.5 MB</strong> arrive through the cloud. A larger one is <code>502 RESPONSE_TOO_LARGE</code>: never truncated, never replaced by a download link. Narrow the period, or use the Local request on the PC.</p>\n<p><strong>Errors:</strong> <code>409 BUSY_REPORT_PROVIDER_UNSUPPORTED</code> (Access), <code>409 BUSY_REPORT_ACCOUNT_CHANGED</code>, <code>409 BUSY_COM_SIGN_IN_UNSUPPORTED</code>; <code>422 BUSY_DATA_INCONSISTENT</code>, <code>RESULT_TOO_LARGE</code> (over 8 MiB on the PC), <code>BUSY_COM_PDF_BLANK</code>; <code>502 BUSY_COM_PDF_FAILED</code> / <code>_HELPER_FAILED</code> / <code>_PDF_MISSING</code> / <code>_PDF_INVALID</code> (retryable); <code>503 BUSY_COM_*</code> (fix the PC, or <code>QUEUE_TIMEOUT</code> / <code>OPEN_FAILED</code> / <code>BUSY_CREDENTIAL_UNAVAILABLE</code> retryable); <code>504 BUSY_COM_TIMEOUT</code>, <code>RELAY_TIMEOUT</code> (retryable). Saved examples are synthetic.</p>\n","urlObject":{"path":["v1","account-ledger-pdf"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"2392ef7d-430c-bb0b-79de-ae490043c5d9","name":"200 – Account Ledger PDF (synthetic, tiny PDF)","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": 7101 },\n  \"fromDate\": \"2026-04-01\",\n  \"toDate\": \"2026-06-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/account-ledger-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /v1/account-ledger-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Cloud** · `POST {{cloudBaseUrl}}/v1/account-ledger-pdf` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · Read only — BUSY prints a report; nothing in BUSY changes\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version with the report PDFs (Windows `75d5602` or later — **not** in public release 0.0.12); an earlier one answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`).\n**Required:** `companyCode`, `financialYear`, `account` · **Optional:** `fromDate`, `toDate` · operation `busy.reports.account-ledger.pdf`\n**Answer:** `{ success, data, metadata }` as the Local API answers it.\n\n---\n\n**Same body and answer as the Local request *Local PC → Report PDFs → Account Ledger PDF*, through the Cloud Relay.** One account's **Account Ledger** (BUSY report 19) printed by BUSY's own report printing on the online PC: the opening balance at `fromDate`, every entry of the period with its running balance, totals and the closing balance. A document: no `Idempotency-Key`, no `script`; a failed or timed-out call may be repeated (it writes nothing).\n\n**Body:** `account` = exactly one of `{ \"code\": n }` (1-2147483647) or `{ \"name\": \"…\" }` (1-60, compared without case and surrounding spaces); an account master only (a group's or item's code is `404 NOT_FOUND`), refused `422 MASTER_REFERENCE_AMBIGUOUS` when another account holds its name as a name or alias. `fromDate` / `toDate`: exactly `YYYY-MM-DD`, real dates inside the selected financial year, `fromDate` ≤ `toDate` (`400 INVALID_PARAMETER`, checked in the cloud — BUSY validates none of them); default the whole year. Unknown members (`formatName`, `startDate` …) are `400 BAD_REQUEST`. Body ≤ 16 KiB.\n\n**Answer:** `data` = `{ fileName (AccountLedger-<company>-<year>-<account code>-<from>-<to>.pdf), mimeType, byteLength, sha256, pages, contentBase64 }` — decode `contentBase64` (standard base64, one line); its SHA-256 is `sha256`. `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"accountLedger\"), busyReportId (19), account { code, name }, fromDate, toDate, elapsedMs, executedAt`.\n\n**⚠ Size limitation:** the PC prints up to 8 MiB, but a relayed answer — base64 and envelope included — is limited to **2 MiB**, so only PDFs up to **about 1.5 MB** arrive through the cloud. A larger one is `502 RESPONSE_TOO_LARGE`: never truncated, never replaced by a download link. Narrow the period, or use the Local request on the PC.\n\n**Errors:** `409 BUSY_REPORT_PROVIDER_UNSUPPORTED` (Access), `409 BUSY_REPORT_ACCOUNT_CHANGED`, `409 BUSY_COM_SIGN_IN_UNSUPPORTED`; `422 BUSY_DATA_INCONSISTENT`, `RESULT_TOO_LARGE` (over 8 MiB on the PC), `BUSY_COM_PDF_BLANK`; `502 BUSY_COM_PDF_FAILED` / `_HELPER_FAILED` / `_PDF_MISSING` / `_PDF_INVALID` (retryable); `503 BUSY_COM_*` (fix the PC, or `QUEUE_TIMEOUT` / `OPEN_FAILED` / `BUSY_CREDENTIAL_UNAVAILABLE` retryable); `504 BUSY_COM_TIMEOUT`, `RELAY_TIMEOUT` (retryable). Saved examples are synthetic."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000201","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"fileName\": \"AccountLedger-COMP0001-2026-7101-2026-04-01-2026-06-30.pdf\",\n    \"mimeType\": \"application/pdf\",\n    \"byteLength\": 54,\n    \"sha256\": \"489ffb43555619d787dcc6b7d2117d4a061970f975a531e413b8b4f74f4ca303\",\n    \"pages\": 1,\n    \"contentBase64\": \"JVBERi0xLjQKJSBzeW50aGV0aWMgZXhhbXBsZSwgbm90IGEgcmVhbCByZXBvcnQKJSVFT0YK\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.reports.account-ledger.pdf\",\n    \"requestId\": \"rq_0SYNTHET1C0000000000000201\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"report\": \"accountLedger\",\n    \"busyReportId\": 19,\n    \"account\": { \"code\": 7101, \"name\": \"Synthetic Traders\" },\n    \"fromDate\": \"2026-04-01\",\n    \"toDate\": \"2026-06-30\",\n    \"elapsedMs\": 4180,\n    \"executedAt\": \"2026-10-16T10:00:00+00:00\"\n  }\n}"},{"id":"f3c2c0ac-8e0d-9e2d-5e68-8aaff887c47d","name":"400 – toDate outside the selected financial year (refused by the cloud) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": 7101 },\n  \"fromDate\": \"2026-04-01\",\n  \"toDate\": \"2026-06-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/account-ledger-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /v1/account-ledger-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Cloud** · `POST {{cloudBaseUrl}}/v1/account-ledger-pdf` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · Read only — BUSY prints a report; nothing in BUSY changes\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version with the report PDFs (Windows `75d5602` or later — **not** in public release 0.0.12); an earlier one answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`).\n**Required:** `companyCode`, `financialYear`, `account` · **Optional:** `fromDate`, `toDate` · operation `busy.reports.account-ledger.pdf`\n**Answer:** `{ success, data, metadata }` as the Local API answers it.\n\n---\n\n**Same body and answer as the Local request *Local PC → Report PDFs → Account Ledger PDF*, through the Cloud Relay.** One account's **Account Ledger** (BUSY report 19) printed by BUSY's own report printing on the online PC: the opening balance at `fromDate`, every entry of the period with its running balance, totals and the closing balance. A document: no `Idempotency-Key`, no `script`; a failed or timed-out call may be repeated (it writes nothing).\n\n**Body:** `account` = exactly one of `{ \"code\": n }` (1-2147483647) or `{ \"name\": \"…\" }` (1-60, compared without case and surrounding spaces); an account master only (a group's or item's code is `404 NOT_FOUND`), refused `422 MASTER_REFERENCE_AMBIGUOUS` when another account holds its name as a name or alias. `fromDate` / `toDate`: exactly `YYYY-MM-DD`, real dates inside the selected financial year, `fromDate` ≤ `toDate` (`400 INVALID_PARAMETER`, checked in the cloud — BUSY validates none of them); default the whole year. Unknown members (`formatName`, `startDate` …) are `400 BAD_REQUEST`. Body ≤ 16 KiB.\n\n**Answer:** `data` = `{ fileName (AccountLedger-<company>-<year>-<account code>-<from>-<to>.pdf), mimeType, byteLength, sha256, pages, contentBase64 }` — decode `contentBase64` (standard base64, one line); its SHA-256 is `sha256`. `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"accountLedger\"), busyReportId (19), account { code, name }, fromDate, toDate, elapsedMs, executedAt`.\n\n**⚠ Size limitation:** the PC prints up to 8 MiB, but a relayed answer — base64 and envelope included — is limited to **2 MiB**, so only PDFs up to **about 1.5 MB** arrive through the cloud. A larger one is `502 RESPONSE_TOO_LARGE`: never truncated, never replaced by a download link. Narrow the period, or use the Local request on the PC.\n\n**Errors:** `409 BUSY_REPORT_PROVIDER_UNSUPPORTED` (Access), `409 BUSY_REPORT_ACCOUNT_CHANGED`, `409 BUSY_COM_SIGN_IN_UNSUPPORTED`; `422 BUSY_DATA_INCONSISTENT`, `RESULT_TOO_LARGE` (over 8 MiB on the PC), `BUSY_COM_PDF_BLANK`; `502 BUSY_COM_PDF_FAILED` / `_HELPER_FAILED` / `_PDF_MISSING` / `_PDF_INVALID` (retryable); `503 BUSY_COM_*` (fix the PC, or `QUEUE_TIMEOUT` / `OPEN_FAILED` / `BUSY_CREDENTIAL_UNAVAILABLE` retryable); `504 BUSY_COM_TIMEOUT`, `RELAY_TIMEOUT` (retryable). Saved examples are synthetic."},"status":"Bad Request","code":400,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"INVALID_PARAMETER\",\n      \"message\": \"toDate must be inside the selected financial year (2026-04-01 to 2027-03-31).\",\n      \"field\": \"toDate\"\n    },\n    \"requestId\": \"00000000-5e5e-4000-8000-000000000201\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"7121a1f4-c6fd-a20a-282c-91ae1e28780d","name":"502 – RESPONSE_TOO_LARGE: the PDF does not fit the relay's 2 MiB answer (never truncated, no link) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": 7101 },\n  \"fromDate\": \"2026-04-01\",\n  \"toDate\": \"2026-06-30\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/account-ledger-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /v1/account-ledger-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Cloud** · `POST {{cloudBaseUrl}}/v1/account-ledger-pdf` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · Read only — BUSY prints a report; nothing in BUSY changes\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version with the report PDFs (Windows `75d5602` or later — **not** in public release 0.0.12); an earlier one answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`).\n**Required:** `companyCode`, `financialYear`, `account` · **Optional:** `fromDate`, `toDate` · operation `busy.reports.account-ledger.pdf`\n**Answer:** `{ success, data, metadata }` as the Local API answers it.\n\n---\n\n**Same body and answer as the Local request *Local PC → Report PDFs → Account Ledger PDF*, through the Cloud Relay.** One account's **Account Ledger** (BUSY report 19) printed by BUSY's own report printing on the online PC: the opening balance at `fromDate`, every entry of the period with its running balance, totals and the closing balance. A document: no `Idempotency-Key`, no `script`; a failed or timed-out call may be repeated (it writes nothing).\n\n**Body:** `account` = exactly one of `{ \"code\": n }` (1-2147483647) or `{ \"name\": \"…\" }` (1-60, compared without case and surrounding spaces); an account master only (a group's or item's code is `404 NOT_FOUND`), refused `422 MASTER_REFERENCE_AMBIGUOUS` when another account holds its name as a name or alias. `fromDate` / `toDate`: exactly `YYYY-MM-DD`, real dates inside the selected financial year, `fromDate` ≤ `toDate` (`400 INVALID_PARAMETER`, checked in the cloud — BUSY validates none of them); default the whole year. Unknown members (`formatName`, `startDate` …) are `400 BAD_REQUEST`. Body ≤ 16 KiB.\n\n**Answer:** `data` = `{ fileName (AccountLedger-<company>-<year>-<account code>-<from>-<to>.pdf), mimeType, byteLength, sha256, pages, contentBase64 }` — decode `contentBase64` (standard base64, one line); its SHA-256 is `sha256`. `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"accountLedger\"), busyReportId (19), account { code, name }, fromDate, toDate, elapsedMs, executedAt`.\n\n**⚠ Size limitation:** the PC prints up to 8 MiB, but a relayed answer — base64 and envelope included — is limited to **2 MiB**, so only PDFs up to **about 1.5 MB** arrive through the cloud. A larger one is `502 RESPONSE_TOO_LARGE`: never truncated, never replaced by a download link. Narrow the period, or use the Local request on the PC.\n\n**Errors:** `409 BUSY_REPORT_PROVIDER_UNSUPPORTED` (Access), `409 BUSY_REPORT_ACCOUNT_CHANGED`, `409 BUSY_COM_SIGN_IN_UNSUPPORTED`; `422 BUSY_DATA_INCONSISTENT`, `RESULT_TOO_LARGE` (over 8 MiB on the PC), `BUSY_COM_PDF_BLANK`; `502 BUSY_COM_PDF_FAILED` / `_HELPER_FAILED` / `_PDF_MISSING` / `_PDF_INVALID` (retryable); `503 BUSY_COM_*` (fix the PC, or `QUEUE_TIMEOUT` / `OPEN_FAILED` / `BUSY_CREDENTIAL_UNAVAILABLE` retryable); `504 BUSY_COM_TIMEOUT`, `RELAY_TIMEOUT` (retryable). Saved examples are synthetic."},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000202"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"RESPONSE_TOO_LARGE\",\n      \"message\": \"The result was larger than this API returns.\",\n      \"details\": { \"maxResponseBytes\": 2097152 }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000202\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"f7f3ecd0-ee7c-aaea-c10f-6b5233bb8367"},{"name":"⚠ busy.reports.bills-receivable.pdf – Bills Receivable PDF","id":"6c7de6dc-e8a4-86a4-1f43-9fd82b02a426","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": 7101 },\n  \"status\": \"pending\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/bills-receivable-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /v1/bills-receivable-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.</p>\n<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/bills-receivable-pdf</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — BUSY prints a report; nothing in BUSY changes\n<strong>Status (2026-10-23):</strong> deployed and live (release <code>790395a</code>). The PC needs an AI Zeny version with the report PDFs (Windows <code>75d5602</code> or later — <strong>not</strong> in public release 0.0.12); an earlier one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>).\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>account</code> · <strong>Optional:</strong> <code>asOfDate</code>, <code>status</code> · operation <code>busy.reports.bills-receivable.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body and answer as the Local request <em>Local PC → Report PDFs → Bills Receivable PDF</em>, through the Cloud Relay.</strong> One account's <strong>Bills Receivable</strong> report (BUSY report 201, receivable side) printed by BUSY on the online PC: its receivable bill references as on <code>asOfDate</code>. A document: no <code>Idempotency-Key</code>, no <code>script</code>; repeatable (it writes nothing).</p>\n<p><strong>Body:</strong> <code>account</code> = exactly one of <code>{ \"code\": n }</code> or <code>{ \"name\": \"…\" }</code>; an account master <strong>kept bill by bill</strong> in BUSY (else <code>422 REPORT_ACCOUNT_NOT_BILL_BY_BILL</code>: use the Account Ledger PDF), whose name no other account holds as a name or alias (<code>422 MASTER_REFERENCE_AMBIGUOUS</code>). <code>asOfDate</code>: <code>YYYY-MM-DD</code> inside the selected year (<code>400</code>); absent = today in India, kept inside the year (decided on the PC). <code>status</code> (exact case): <code>pending</code> (default; every bill still outstanding), <code>overdue</code> (outstanding and due on or before <code>asOfDate</code>), <code>all</code> (every bill reference, settled ones with pending 0). Advances, other credit references and on-account entries are not in this report. Body ≤ 16 KiB.</p>\n<p><strong>Answer:</strong> <code>data</code> = <code>{ fileName (BillsReceivable-&lt;company&gt;-&lt;year&gt;-&lt;account code&gt;-&lt;asOf&gt;-&lt;status&gt;.pdf), mimeType, byteLength, sha256, pages, contentBase64 }</code>; <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, report (\"billsReceivable\"), busyReportId (201), account { code, name }, asOfDate, status, elapsedMs, executedAt</code>.</p>\n<p><strong>⚠ Size limitation:</strong> the PC prints up to 8 MiB, but a relayed answer — base64 and envelope included — is limited to <strong>2 MiB</strong>, so only PDFs up to <strong>about 1.5 MB</strong> arrive through the cloud. A larger one is <code>502 RESPONSE_TOO_LARGE</code>: never truncated, never replaced by a download link.</p>\n<p><strong>Errors:</strong> as the Account Ledger PDF, plus <code>422 REPORT_ACCOUNT_NOT_BILL_BY_BILL</code> and <code>400</code> on <code>status</code>. Saved examples are synthetic.</p>\n","urlObject":{"path":["v1","bills-receivable-pdf"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"8a89fd0e-e2bc-adb9-ec42-6f74a784a4bc","name":"200 – Bills Receivable PDF, overdue (synthetic, tiny PDF)","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": 7101 },\n  \"status\": \"pending\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/bills-receivable-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /v1/bills-receivable-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Cloud** · `POST {{cloudBaseUrl}}/v1/bills-receivable-pdf` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · Read only — BUSY prints a report; nothing in BUSY changes\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version with the report PDFs (Windows `75d5602` or later — **not** in public release 0.0.12); an earlier one answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`).\n**Required:** `companyCode`, `financialYear`, `account` · **Optional:** `asOfDate`, `status` · operation `busy.reports.bills-receivable.pdf`\n**Answer:** `{ success, data, metadata }` as the Local API answers it.\n\n---\n\n**Same body and answer as the Local request *Local PC → Report PDFs → Bills Receivable PDF*, through the Cloud Relay.** One account's **Bills Receivable** report (BUSY report 201, receivable side) printed by BUSY on the online PC: its receivable bill references as on `asOfDate`. A document: no `Idempotency-Key`, no `script`; repeatable (it writes nothing).\n\n**Body:** `account` = exactly one of `{ \"code\": n }` or `{ \"name\": \"…\" }`; an account master **kept bill by bill** in BUSY (else `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`: use the Account Ledger PDF), whose name no other account holds as a name or alias (`422 MASTER_REFERENCE_AMBIGUOUS`). `asOfDate`: `YYYY-MM-DD` inside the selected year (`400`); absent = today in India, kept inside the year (decided on the PC). `status` (exact case): `pending` (default; every bill still outstanding), `overdue` (outstanding and due on or before `asOfDate`), `all` (every bill reference, settled ones with pending 0). Advances, other credit references and on-account entries are not in this report. Body ≤ 16 KiB.\n\n**Answer:** `data` = `{ fileName (BillsReceivable-<company>-<year>-<account code>-<asOf>-<status>.pdf), mimeType, byteLength, sha256, pages, contentBase64 }`; `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"billsReceivable\"), busyReportId (201), account { code, name }, asOfDate, status, elapsedMs, executedAt`.\n\n**⚠ Size limitation:** the PC prints up to 8 MiB, but a relayed answer — base64 and envelope included — is limited to **2 MiB**, so only PDFs up to **about 1.5 MB** arrive through the cloud. A larger one is `502 RESPONSE_TOO_LARGE`: never truncated, never replaced by a download link.\n\n**Errors:** as the Account Ledger PDF, plus `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL` and `400` on `status`. Saved examples are synthetic."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000203","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"fileName\": \"BillsReceivable-COMP0001-2026-7101-2026-09-30-overdue.pdf\",\n    \"mimeType\": \"application/pdf\",\n    \"byteLength\": 54,\n    \"sha256\": \"489ffb43555619d787dcc6b7d2117d4a061970f975a531e413b8b4f74f4ca303\",\n    \"pages\": 1,\n    \"contentBase64\": \"JVBERi0xLjQKJSBzeW50aGV0aWMgZXhhbXBsZSwgbm90IGEgcmVhbCByZXBvcnQKJSVFT0YK\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.reports.bills-receivable.pdf\",\n    \"requestId\": \"rq_0SYNTHET1C0000000000000203\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"report\": \"billsReceivable\",\n    \"busyReportId\": 201,\n    \"account\": { \"code\": 7101, \"name\": \"Synthetic Traders\" },\n    \"asOfDate\": \"2026-09-30\",\n    \"status\": \"overdue\",\n    \"elapsedMs\": 3960,\n    \"executedAt\": \"2026-10-16T10:00:00+00:00\"\n  }\n}"},{"id":"1f49d704-d7d2-a251-b27e-ca0f196a2395","name":"422 – REPORT_ACCOUNT_NOT_BILL_BY_BILL [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": 7101 },\n  \"status\": \"pending\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/bills-receivable-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /v1/bills-receivable-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Cloud** · `POST {{cloudBaseUrl}}/v1/bills-receivable-pdf` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · Read only — BUSY prints a report; nothing in BUSY changes\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version with the report PDFs (Windows `75d5602` or later — **not** in public release 0.0.12); an earlier one answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`).\n**Required:** `companyCode`, `financialYear`, `account` · **Optional:** `asOfDate`, `status` · operation `busy.reports.bills-receivable.pdf`\n**Answer:** `{ success, data, metadata }` as the Local API answers it.\n\n---\n\n**Same body and answer as the Local request *Local PC → Report PDFs → Bills Receivable PDF*, through the Cloud Relay.** One account's **Bills Receivable** report (BUSY report 201, receivable side) printed by BUSY on the online PC: its receivable bill references as on `asOfDate`. A document: no `Idempotency-Key`, no `script`; repeatable (it writes nothing).\n\n**Body:** `account` = exactly one of `{ \"code\": n }` or `{ \"name\": \"…\" }`; an account master **kept bill by bill** in BUSY (else `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`: use the Account Ledger PDF), whose name no other account holds as a name or alias (`422 MASTER_REFERENCE_AMBIGUOUS`). `asOfDate`: `YYYY-MM-DD` inside the selected year (`400`); absent = today in India, kept inside the year (decided on the PC). `status` (exact case): `pending` (default; every bill still outstanding), `overdue` (outstanding and due on or before `asOfDate`), `all` (every bill reference, settled ones with pending 0). Advances, other credit references and on-account entries are not in this report. Body ≤ 16 KiB.\n\n**Answer:** `data` = `{ fileName (BillsReceivable-<company>-<year>-<account code>-<asOf>-<status>.pdf), mimeType, byteLength, sha256, pages, contentBase64 }`; `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"billsReceivable\"), busyReportId (201), account { code, name }, asOfDate, status, elapsedMs, executedAt`.\n\n**⚠ Size limitation:** the PC prints up to 8 MiB, but a relayed answer — base64 and envelope included — is limited to **2 MiB**, so only PDFs up to **about 1.5 MB** arrive through the cloud. A larger one is `502 RESPONSE_TOO_LARGE`: never truncated, never replaced by a download link.\n\n**Errors:** as the Account Ledger PDF, plus `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL` and `400` on `status`. Saved examples are synthetic."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000204"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"REPORT_ACCOUNT_NOT_BILL_BY_BILL\",\n      \"message\": \"BUSY does not keep this account bill by bill, so it has no bill-wise receivables. Use the Account Ledger PDF for it.\",\n      \"field\": \"account\"\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000204\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"b3859990-df84-21e4-82ca-0fa010d69785","name":"502 – RESPONSE_TOO_LARGE: over the relay's 2 MiB answer (never truncated, no link) [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": 7101 },\n  \"status\": \"pending\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/bills-receivable-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /v1/bills-receivable-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Cloud** · `POST {{cloudBaseUrl}}/v1/bills-receivable-pdf` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · Read only — BUSY prints a report; nothing in BUSY changes\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version with the report PDFs (Windows `75d5602` or later — **not** in public release 0.0.12); an earlier one answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`).\n**Required:** `companyCode`, `financialYear`, `account` · **Optional:** `asOfDate`, `status` · operation `busy.reports.bills-receivable.pdf`\n**Answer:** `{ success, data, metadata }` as the Local API answers it.\n\n---\n\n**Same body and answer as the Local request *Local PC → Report PDFs → Bills Receivable PDF*, through the Cloud Relay.** One account's **Bills Receivable** report (BUSY report 201, receivable side) printed by BUSY on the online PC: its receivable bill references as on `asOfDate`. A document: no `Idempotency-Key`, no `script`; repeatable (it writes nothing).\n\n**Body:** `account` = exactly one of `{ \"code\": n }` or `{ \"name\": \"…\" }`; an account master **kept bill by bill** in BUSY (else `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`: use the Account Ledger PDF), whose name no other account holds as a name or alias (`422 MASTER_REFERENCE_AMBIGUOUS`). `asOfDate`: `YYYY-MM-DD` inside the selected year (`400`); absent = today in India, kept inside the year (decided on the PC). `status` (exact case): `pending` (default; every bill still outstanding), `overdue` (outstanding and due on or before `asOfDate`), `all` (every bill reference, settled ones with pending 0). Advances, other credit references and on-account entries are not in this report. Body ≤ 16 KiB.\n\n**Answer:** `data` = `{ fileName (BillsReceivable-<company>-<year>-<account code>-<asOf>-<status>.pdf), mimeType, byteLength, sha256, pages, contentBase64 }`; `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"billsReceivable\"), busyReportId (201), account { code, name }, asOfDate, status, elapsedMs, executedAt`.\n\n**⚠ Size limitation:** the PC prints up to 8 MiB, but a relayed answer — base64 and envelope included — is limited to **2 MiB**, so only PDFs up to **about 1.5 MB** arrive through the cloud. A larger one is `502 RESPONSE_TOO_LARGE`: never truncated, never replaced by a download link.\n\n**Errors:** as the Account Ledger PDF, plus `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL` and `400` on `status`. Saved examples are synthetic."},"status":"Bad Gateway","code":502,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000205","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"RESPONSE_TOO_LARGE\",\n      \"message\": \"The result was larger than this API returns.\",\n      \"details\": { \"maxResponseBytes\": 2097152 }\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000205\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"6c7de6dc-e8a4-86a4-1f43-9fd82b02a426"},{"name":"⚠ busy.reports.payment-reminder.pdf – Payment Reminder PDF","id":"6367e4e0-f9ae-150e-f543-53be7a0bc956","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": 7101 },\n  \"bills\": \"pending\",\n  \"itemDetails\": false,\n  \"boldDueBills\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/payment-reminder-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /v1/payment-reminder-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.</p>\n<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/payment-reminder-pdf</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — BUSY prints a report; nothing in BUSY changes\n<strong>Status (2026-10-23):</strong> deployed and live (release <code>790395a</code>). The PC needs an AI Zeny version with the report PDFs (Windows <code>75d5602</code> or later — <strong>not</strong> in public release 0.0.12); an earlier one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>).\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>account</code> · <strong>Optional:</strong> <code>asOfDate</code>, <code>bills</code>, <code>formatName</code>, <code>itemDetails</code>, <code>boldDueBills</code> · operation <code>busy.reports.payment-reminder.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body and answer as the Local request <em>Local PC → Report PDFs → Payment Reminder PDF</em>, through the Cloud Relay.</strong> One customer account's <strong>Payment Reminder</strong> letter (BUSY report 150), <strong>single-account scope only</strong> (the tested scope; no group, all-accounts, selected-accounts, branch, series or optional-field filter). A document: no <code>Idempotency-Key</code>, no <code>script</code>; repeatable (it writes nothing).</p>\n<p><strong>Body:</strong> <code>account</code> as the bills reports (kept bill by bill, else <code>422 REPORT_ACCOUNT_NOT_BILL_BY_BILL</code>). <code>asOfDate</code> <code>YYYY-MM-DD</code> inside the year (absent = today in India, kept inside the year). <code>bills</code> (exact): <code>pending</code> (default; every bill outstanding) or <code>due</code> (outstanding and due on or before <code>asOfDate</code>). <code>formatName</code>: one of the company's Payment Reminder formats, exactly as named, 1-64 characters, no surrounding spaces or control characters (<code>400</code>); not found → <code>404 NOT_FOUND</code> (field <code>formatName</code>, the message lists the formats); absent → <code>STANDARD</code>, and a company without it → <code>409 BUSY_PRINT_FORMAT_MISSING</code> (never created). <code>itemDetails</code> (default false), <code>boldDueBills</code> (default true). Body ≤ 16 KiB.</p>\n<p><strong>Answer:</strong> <code>data</code> = <code>{ fileName (PaymentReminder-&lt;company&gt;-&lt;year&gt;-&lt;account code&gt;-&lt;asOf&gt;-&lt;bills&gt;.pdf), mimeType, byteLength, sha256, pages, contentBase64 }</code>; <code>metadata</code> = <code>apiVersion, operation, requestId, companyCode, financialYear, report (\"paymentReminder\"), busyReportId (150), account { code, name }, asOfDate, bills, formatSource (\"default\" | \"selected\"), formatName, itemDetails, boldDueBills, elapsedMs, executedAt</code>.</p>\n<p><strong>⚠ Size limitation:</strong> the PC prints up to 8 MiB, but a relayed answer — base64 and envelope included — is limited to <strong>2 MiB</strong>, so only PDFs up to <strong>about 1.5 MB</strong> arrive through the cloud. A larger one is <code>502 RESPONSE_TOO_LARGE</code>: never truncated, never replaced by a download link.</p>\n<p><strong>Errors:</strong> as the Account Ledger PDF, plus <code>422 REPORT_ACCOUNT_NOT_BILL_BY_BILL</code>, <code>404 NOT_FOUND</code> (<code>formatName</code>), <code>409 BUSY_PRINT_FORMAT_MISSING</code>. Upgrade note: the letter's form rests on the BUSY version installed when it was proven; re-check after a BUSY upgrade. Saved examples are synthetic.</p>\n","urlObject":{"path":["v1","payment-reminder-pdf"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"76e6d5c6-194e-0d91-27f8-29554f096aa1","name":"200 – Payment Reminder PDF, pending bills, STANDARD format (synthetic, tiny PDF)","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": 7101 },\n  \"bills\": \"pending\",\n  \"itemDetails\": false,\n  \"boldDueBills\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/payment-reminder-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /v1/payment-reminder-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Cloud** · `POST {{cloudBaseUrl}}/v1/payment-reminder-pdf` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · Read only — BUSY prints a report; nothing in BUSY changes\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version with the report PDFs (Windows `75d5602` or later — **not** in public release 0.0.12); an earlier one answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`).\n**Required:** `companyCode`, `financialYear`, `account` · **Optional:** `asOfDate`, `bills`, `formatName`, `itemDetails`, `boldDueBills` · operation `busy.reports.payment-reminder.pdf`\n**Answer:** `{ success, data, metadata }` as the Local API answers it.\n\n---\n\n**Same body and answer as the Local request *Local PC → Report PDFs → Payment Reminder PDF*, through the Cloud Relay.** One customer account's **Payment Reminder** letter (BUSY report 150), **single-account scope only** (the tested scope; no group, all-accounts, selected-accounts, branch, series or optional-field filter). A document: no `Idempotency-Key`, no `script`; repeatable (it writes nothing).\n\n**Body:** `account` as the bills reports (kept bill by bill, else `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`). `asOfDate` `YYYY-MM-DD` inside the year (absent = today in India, kept inside the year). `bills` (exact): `pending` (default; every bill outstanding) or `due` (outstanding and due on or before `asOfDate`). `formatName`: one of the company's Payment Reminder formats, exactly as named, 1-64 characters, no surrounding spaces or control characters (`400`); not found → `404 NOT_FOUND` (field `formatName`, the message lists the formats); absent → `STANDARD`, and a company without it → `409 BUSY_PRINT_FORMAT_MISSING` (never created). `itemDetails` (default false), `boldDueBills` (default true). Body ≤ 16 KiB.\n\n**Answer:** `data` = `{ fileName (PaymentReminder-<company>-<year>-<account code>-<asOf>-<bills>.pdf), mimeType, byteLength, sha256, pages, contentBase64 }`; `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"paymentReminder\"), busyReportId (150), account { code, name }, asOfDate, bills, formatSource (\"default\" | \"selected\"), formatName, itemDetails, boldDueBills, elapsedMs, executedAt`.\n\n**⚠ Size limitation:** the PC prints up to 8 MiB, but a relayed answer — base64 and envelope included — is limited to **2 MiB**, so only PDFs up to **about 1.5 MB** arrive through the cloud. A larger one is `502 RESPONSE_TOO_LARGE`: never truncated, never replaced by a download link.\n\n**Errors:** as the Account Ledger PDF, plus `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`, `404 NOT_FOUND` (`formatName`), `409 BUSY_PRINT_FORMAT_MISSING`. Upgrade note: the letter's form rests on the BUSY version installed when it was proven; re-check after a BUSY upgrade. Saved examples are synthetic."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000206"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"fileName\": \"PaymentReminder-COMP0001-2026-7101-2026-10-16-pending.pdf\",\n    \"mimeType\": \"application/pdf\",\n    \"byteLength\": 54,\n    \"sha256\": \"489ffb43555619d787dcc6b7d2117d4a061970f975a531e413b8b4f74f4ca303\",\n    \"pages\": 1,\n    \"contentBase64\": \"JVBERi0xLjQKJSBzeW50aGV0aWMgZXhhbXBsZSwgbm90IGEgcmVhbCByZXBvcnQKJSVFT0YK\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.reports.payment-reminder.pdf\",\n    \"requestId\": \"rq_0SYNTHET1C0000000000000206\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"report\": \"paymentReminder\",\n    \"busyReportId\": 150,\n    \"account\": { \"code\": 7101, \"name\": \"Synthetic Traders\" },\n    \"asOfDate\": \"2026-10-16\",\n    \"bills\": \"pending\",\n    \"formatSource\": \"default\",\n    \"formatName\": \"STANDARD\",\n    \"itemDetails\": false,\n    \"boldDueBills\": true,\n    \"elapsedMs\": 4210,\n    \"executedAt\": \"2026-10-16T07:30:00.0000000Z\"\n  }\n}"},{"id":"dc239683-a973-8c65-a02a-6dd7fa3f67b3","name":"404 – formatName is not a Payment Reminder format of the company [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": 7101 },\n  \"bills\": \"pending\",\n  \"itemDetails\": false,\n  \"boldDueBills\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/payment-reminder-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /v1/payment-reminder-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Cloud** · `POST {{cloudBaseUrl}}/v1/payment-reminder-pdf` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · Read only — BUSY prints a report; nothing in BUSY changes\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version with the report PDFs (Windows `75d5602` or later — **not** in public release 0.0.12); an earlier one answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`).\n**Required:** `companyCode`, `financialYear`, `account` · **Optional:** `asOfDate`, `bills`, `formatName`, `itemDetails`, `boldDueBills` · operation `busy.reports.payment-reminder.pdf`\n**Answer:** `{ success, data, metadata }` as the Local API answers it.\n\n---\n\n**Same body and answer as the Local request *Local PC → Report PDFs → Payment Reminder PDF*, through the Cloud Relay.** One customer account's **Payment Reminder** letter (BUSY report 150), **single-account scope only** (the tested scope; no group, all-accounts, selected-accounts, branch, series or optional-field filter). A document: no `Idempotency-Key`, no `script`; repeatable (it writes nothing).\n\n**Body:** `account` as the bills reports (kept bill by bill, else `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`). `asOfDate` `YYYY-MM-DD` inside the year (absent = today in India, kept inside the year). `bills` (exact): `pending` (default; every bill outstanding) or `due` (outstanding and due on or before `asOfDate`). `formatName`: one of the company's Payment Reminder formats, exactly as named, 1-64 characters, no surrounding spaces or control characters (`400`); not found → `404 NOT_FOUND` (field `formatName`, the message lists the formats); absent → `STANDARD`, and a company without it → `409 BUSY_PRINT_FORMAT_MISSING` (never created). `itemDetails` (default false), `boldDueBills` (default true). Body ≤ 16 KiB.\n\n**Answer:** `data` = `{ fileName (PaymentReminder-<company>-<year>-<account code>-<asOf>-<bills>.pdf), mimeType, byteLength, sha256, pages, contentBase64 }`; `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"paymentReminder\"), busyReportId (150), account { code, name }, asOfDate, bills, formatSource (\"default\" | \"selected\"), formatName, itemDetails, boldDueBills, elapsedMs, executedAt`.\n\n**⚠ Size limitation:** the PC prints up to 8 MiB, but a relayed answer — base64 and envelope included — is limited to **2 MiB**, so only PDFs up to **about 1.5 MB** arrive through the cloud. A larger one is `502 RESPONSE_TOO_LARGE`: never truncated, never replaced by a download link.\n\n**Errors:** as the Account Ledger PDF, plus `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`, `404 NOT_FOUND` (`formatName`), `409 BUSY_PRINT_FORMAT_MISSING`. Upgrade note: the letter's form rests on the BUSY version installed when it was proven; re-check after a BUSY upgrade. Saved examples are synthetic."},"status":"Not Found","code":404,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"X-Request-Id","value":"rq_0SYNTHET1C0000000000000207"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"NOT_FOUND\",\n      \"message\": \"No Payment Reminder format of this company in BUSY has exactly that formatName (names are case-sensitive). Leave formatName out for STANDARD. Available: STANDARD.\",\n      \"field\": \"formatName\"\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000207\",\n    \"apiVersion\": \"v1\"\n  }\n}"},{"id":"ad6c14fa-5132-4a22-b246-5e420d03cb6b","name":"409 – BUSY_PRINT_FORMAT_MISSING: no STANDARD Payment Reminder format [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": 7101 },\n  \"bills\": \"pending\",\n  \"itemDetails\": false,\n  \"boldDueBills\": true\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/payment-reminder-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /v1/payment-reminder-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Cloud** · `POST {{cloudBaseUrl}}/v1/payment-reminder-pdf` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · Read only — BUSY prints a report; nothing in BUSY changes\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version with the report PDFs (Windows `75d5602` or later — **not** in public release 0.0.12); an earlier one answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`).\n**Required:** `companyCode`, `financialYear`, `account` · **Optional:** `asOfDate`, `bills`, `formatName`, `itemDetails`, `boldDueBills` · operation `busy.reports.payment-reminder.pdf`\n**Answer:** `{ success, data, metadata }` as the Local API answers it.\n\n---\n\n**Same body and answer as the Local request *Local PC → Report PDFs → Payment Reminder PDF*, through the Cloud Relay.** One customer account's **Payment Reminder** letter (BUSY report 150), **single-account scope only** (the tested scope; no group, all-accounts, selected-accounts, branch, series or optional-field filter). A document: no `Idempotency-Key`, no `script`; repeatable (it writes nothing).\n\n**Body:** `account` as the bills reports (kept bill by bill, else `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`). `asOfDate` `YYYY-MM-DD` inside the year (absent = today in India, kept inside the year). `bills` (exact): `pending` (default; every bill outstanding) or `due` (outstanding and due on or before `asOfDate`). `formatName`: one of the company's Payment Reminder formats, exactly as named, 1-64 characters, no surrounding spaces or control characters (`400`); not found → `404 NOT_FOUND` (field `formatName`, the message lists the formats); absent → `STANDARD`, and a company without it → `409 BUSY_PRINT_FORMAT_MISSING` (never created). `itemDetails` (default false), `boldDueBills` (default true). Body ≤ 16 KiB.\n\n**Answer:** `data` = `{ fileName (PaymentReminder-<company>-<year>-<account code>-<asOf>-<bills>.pdf), mimeType, byteLength, sha256, pages, contentBase64 }`; `metadata` = `apiVersion, operation, requestId, companyCode, financialYear, report (\"paymentReminder\"), busyReportId (150), account { code, name }, asOfDate, bills, formatSource (\"default\" | \"selected\"), formatName, itemDetails, boldDueBills, elapsedMs, executedAt`.\n\n**⚠ Size limitation:** the PC prints up to 8 MiB, but a relayed answer — base64 and envelope included — is limited to **2 MiB**, so only PDFs up to **about 1.5 MB** arrive through the cloud. A larger one is `502 RESPONSE_TOO_LARGE`: never truncated, never replaced by a download link.\n\n**Errors:** as the Account Ledger PDF, plus `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`, `404 NOT_FOUND` (`formatName`), `409 BUSY_PRINT_FORMAT_MISSING`. Upgrade note: the letter's form rests on the BUSY version installed when it was proven; re-check after a BUSY upgrade. Saved examples are synthetic."},"status":"Conflict","code":409,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000208","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"BUSY_PRINT_FORMAT_MISSING\",\n      \"message\": \"This company has no STANDARD Payment Reminder format in BUSY. AI Zeny never creates a format or uses another one instead. Set up the STANDARD Payment Reminder format in BUSY, or send formatName with one of the company's Payment Reminder formats.\",\n      \"field\": \"formatName\"\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000208\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"6367e4e0-f9ae-150e-f543-53be7a0bc956"},{"name":"⚠ busy.reports.bills-payable.pdf – Bills Payable PDF","id":"78c15a40-ba1c-6a97-7dd1-05411f120b4d","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": 7201 },\n  \"status\": \"pending\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/bills-payable-pdf","description":"<p>⚠ PDF guard: skipped unless current <code>confirmMutating</code> is <code>yes</code> and <code>confirmHighImpact</code> is <code>POST /v1/bills-payable-pdf</code>. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.</p>\n<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/bills-payable-pdf</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · Read only — BUSY prints a report; nothing in BUSY changes\n<strong>Status (2026-10-23):</strong> deployed and live (release <code>790395a</code>). The PC needs an AI Zeny version with the report PDFs (Windows <code>75d5602</code> or later — <strong>not</strong> in public release 0.0.12); an earlier one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>).\n<strong>Required:</strong> <code>companyCode</code>, <code>financialYear</code>, <code>account</code> · <strong>Optional:</strong> <code>asOfDate</code>, <code>status</code> · operation <code>busy.reports.bills-payable.pdf</code>\n<strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it.</p>\n<hr />\n<p><strong>Same body and answer as the Local request <em>Local PC → Report PDFs → Bills Payable PDF</em>, through the Cloud Relay.</strong> One account's <strong>Bills Payable</strong> report (BUSY report 201, payable side) printed by BUSY on the online PC: its payable bill references as on <code>asOfDate</code>. Values as BUSY prints them (an over-settled reference shows a negative pending amount); the supplier's advances and other debit references are not in it and are never netted. A document: no <code>Idempotency-Key</code>, no <code>script</code>; repeatable (it writes nothing).</p>\n<p><strong>Body:</strong> the Bills Receivable PDF's body — <code>account</code> (kept bill by bill, else <code>422 REPORT_ACCOUNT_NOT_BILL_BY_BILL</code>; no name/alias clash, else <code>422 MASTER_REFERENCE_AMBIGUOUS</code>), <code>asOfDate</code> inside the year (absent = today in India, kept inside the year), <code>status</code> <code>pending</code> (default) / <code>overdue</code> / <code>all</code> (exact case). Body ≤ 16 KiB.</p>\n<p><strong>Answer:</strong> <code>data</code> = <code>{ fileName (BillsPayable-&lt;company&gt;-&lt;year&gt;-&lt;account code&gt;-&lt;asOf&gt;-&lt;status&gt;.pdf), mimeType, byteLength, sha256, pages, contentBase64 }</code>; <code>metadata</code> = the Bills Receivable shape with <code>report</code> <code>\"billsPayable\"</code>, <code>busyReportId</code> 201.</p>\n<p><strong>⚠ Size limitation:</strong> the PC prints up to 8 MiB, but a relayed answer — base64 and envelope included — is limited to <strong>2 MiB</strong>, so only PDFs up to <strong>about 1.5 MB</strong> arrive through the cloud. A larger one is <code>502 RESPONSE_TOO_LARGE</code>: never truncated, never replaced by a download link.</p>\n<p><strong>Errors:</strong> as the Account Ledger PDF, plus <code>422 REPORT_ACCOUNT_NOT_BILL_BY_BILL</code> and <code>400</code> on <code>status</code>. Saved examples are synthetic.</p>\n","urlObject":{"path":["v1","bills-payable-pdf"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"a30f231a-1e7e-fbd0-4b87-21e4c33c193e","name":"200 – Bills Payable PDF, all (synthetic, tiny PDF)","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": 7201 },\n  \"status\": \"pending\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/bills-payable-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /v1/bills-payable-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Cloud** · `POST {{cloudBaseUrl}}/v1/bills-payable-pdf` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · Read only — BUSY prints a report; nothing in BUSY changes\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version with the report PDFs (Windows `75d5602` or later — **not** in public release 0.0.12); an earlier one answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`).\n**Required:** `companyCode`, `financialYear`, `account` · **Optional:** `asOfDate`, `status` · operation `busy.reports.bills-payable.pdf`\n**Answer:** `{ success, data, metadata }` as the Local API answers it.\n\n---\n\n**Same body and answer as the Local request *Local PC → Report PDFs → Bills Payable PDF*, through the Cloud Relay.** One account's **Bills Payable** report (BUSY report 201, payable side) printed by BUSY on the online PC: its payable bill references as on `asOfDate`. Values as BUSY prints them (an over-settled reference shows a negative pending amount); the supplier's advances and other debit references are not in it and are never netted. A document: no `Idempotency-Key`, no `script`; repeatable (it writes nothing).\n\n**Body:** the Bills Receivable PDF's body — `account` (kept bill by bill, else `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`; no name/alias clash, else `422 MASTER_REFERENCE_AMBIGUOUS`), `asOfDate` inside the year (absent = today in India, kept inside the year), `status` `pending` (default) / `overdue` / `all` (exact case). Body ≤ 16 KiB.\n\n**Answer:** `data` = `{ fileName (BillsPayable-<company>-<year>-<account code>-<asOf>-<status>.pdf), mimeType, byteLength, sha256, pages, contentBase64 }`; `metadata` = the Bills Receivable shape with `report` `\"billsPayable\"`, `busyReportId` 201.\n\n**⚠ Size limitation:** the PC prints up to 8 MiB, but a relayed answer — base64 and envelope included — is limited to **2 MiB**, so only PDFs up to **about 1.5 MB** arrive through the cloud. A larger one is `502 RESPONSE_TOO_LARGE`: never truncated, never replaced by a download link.\n\n**Errors:** as the Account Ledger PDF, plus `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL` and `400` on `status`. Saved examples are synthetic."},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000209","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": true,\n  \"data\": {\n    \"fileName\": \"BillsPayable-COMP0001-2026-7201-2026-10-16-all.pdf\",\n    \"mimeType\": \"application/pdf\",\n    \"byteLength\": 54,\n    \"sha256\": \"489ffb43555619d787dcc6b7d2117d4a061970f975a531e413b8b4f74f4ca303\",\n    \"pages\": 1,\n    \"contentBase64\": \"JVBERi0xLjQKJSBzeW50aGV0aWMgZXhhbXBsZSwgbm90IGEgcmVhbCByZXBvcnQKJSVFT0YK\"\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"busy.reports.bills-payable.pdf\",\n    \"requestId\": \"rq_0SYNTHET1C0000000000000209\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"report\": \"billsPayable\",\n    \"busyReportId\": 201,\n    \"account\": { \"code\": 7201, \"name\": \"Synthetic Supplies\" },\n    \"asOfDate\": \"2026-10-16\",\n    \"status\": \"all\",\n    \"elapsedMs\": 3880,\n    \"executedAt\": \"2026-10-16T07:31:00.0000000Z\"\n  }\n}"},{"id":"5727d895-22a9-038a-1352-1c6ad0d7bfce","name":"422 – REPORT_ACCOUNT_NOT_BILL_BY_BILL [synthetic]","originalRequest":{"auth":{"type":"bearer","bearer":{"token":"{{cloudApiToken}}"}},"method":"POST","header":[{"value":"application/json","key":"Content-Type"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{companyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"account\": { \"code\": 7201 },\n  \"status\": \"pending\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/bills-payable-pdf","description":"⚠ PDF guard: skipped unless current `confirmMutating` is `yes` and `confirmHighImpact` is `POST /v1/bills-payable-pdf`. Both confirmations clear before one send. Verify the target first; no collection run was performed. Native BUSY report-PDF side effects are unverified.\n\n**Cloud** · `POST {{cloudBaseUrl}}/v1/bills-payable-pdf` · Bearer `{{cloudApiToken}}` (organization token, not the Local API token) · Read only — BUSY prints a report; nothing in BUSY changes\n**Status (2026-10-23):** deployed and live (release `790395a`). The PC needs an AI Zeny version with the report PDFs (Windows `75d5602` or later — **not** in public release 0.0.12); an earlier one answers `502 DEVICE_ERROR` (`details.deviceErrorCode` `REPORT_UNSUPPORTED`).\n**Required:** `companyCode`, `financialYear`, `account` · **Optional:** `asOfDate`, `status` · operation `busy.reports.bills-payable.pdf`\n**Answer:** `{ success, data, metadata }` as the Local API answers it.\n\n---\n\n**Same body and answer as the Local request *Local PC → Report PDFs → Bills Payable PDF*, through the Cloud Relay.** One account's **Bills Payable** report (BUSY report 201, payable side) printed by BUSY on the online PC: its payable bill references as on `asOfDate`. Values as BUSY prints them (an over-settled reference shows a negative pending amount); the supplier's advances and other debit references are not in it and are never netted. A document: no `Idempotency-Key`, no `script`; repeatable (it writes nothing).\n\n**Body:** the Bills Receivable PDF's body — `account` (kept bill by bill, else `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL`; no name/alias clash, else `422 MASTER_REFERENCE_AMBIGUOUS`), `asOfDate` inside the year (absent = today in India, kept inside the year), `status` `pending` (default) / `overdue` / `all` (exact case). Body ≤ 16 KiB.\n\n**Answer:** `data` = `{ fileName (BillsPayable-<company>-<year>-<account code>-<asOf>-<status>.pdf), mimeType, byteLength, sha256, pages, contentBase64 }`; `metadata` = the Bills Receivable shape with `report` `\"billsPayable\"`, `busyReportId` 201.\n\n**⚠ Size limitation:** the PC prints up to 8 MiB, but a relayed answer — base64 and envelope included — is limited to **2 MiB**, so only PDFs up to **about 1.5 MB** arrive through the cloud. A larger one is `502 RESPONSE_TOO_LARGE`: never truncated, never replaced by a download link.\n\n**Errors:** as the Account Ledger PDF, plus `422 REPORT_ACCOUNT_NOT_BILL_BY_BILL` and `400` on `status`. Saved examples are synthetic."},"status":"Unprocessable Entity","code":422,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"},{"value":"rq_0SYNTHET1C0000000000000210","key":"X-Request-Id"}],"cookie":[],"responseTime":null,"body":"{\n  \"success\": false,\n  \"data\": null,\n  \"metadata\": {\n    \"error\": {\n      \"code\": \"REPORT_ACCOUNT_NOT_BILL_BY_BILL\",\n      \"message\": \"BUSY does not keep this account bill by bill, so it has no bill-wise payables. Use the Account Ledger PDF for it.\",\n      \"field\": \"account\"\n    },\n    \"requestId\": \"rq_0SYNTHET1C0000000000000210\",\n    \"apiVersion\": \"v1\"\n  }\n}"}],"_postman_id":"78c15a40-ba1c-6a97-7dd1-05411f120b4d"}],"id":"b34d3eb8-c07f-4142-98d5-9b91d72790cc","description":"<p>Relayed BUSY report printing returns a PDF when the cloud route is deployed. Native report-PDF side effects remain unverified. Treat requests as potentially mutating and require explicit one-send confirmation. No cloud deployment claim is made.</p>\n","_postman_id":"b34d3eb8-c07f-4142-98d5-9b91d72790cc","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"⚠ Execute customer integration (202 acceptance; writes through the PC)","id":"e16be9a2-3d54-9134-f5e5-2c872b6f0ea7","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"value":"application/json","key":"Content-Type"},{"value":"{{cloudIdempotencyKey}}","description":"<p>Kept after an uncertain outcome; minted by the pre-request script only when none is held.</p>\n","key":"Idempotency-Key"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"integrationName\": \"{{integrationName}}\",\n  \"runReference\": \"{{integrationRunReference}}\",\n  \"payload\": {\n    \"records\": [\n      {\n        \"id\": \"SYNTHETIC-001\"\n      }\n    ]\n  },\n  \"parameters\": {}\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/execute-integration","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/execute-integration</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.integrations.execute</code> · <strong>⚠ Writes to BUSY</strong> (guarded: needs <code>confirmMutating</code> = <code>yes</code>; sends an <code>Idempotency-Key</code>)</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Body</strong> (at most 1024 KiB; the PC also accepts at most 64 KiB per signed command): companyCode, financialYear, integrationName, runReference, optional payload/parameters/expectedRevision.</p>\n<p><strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it. <strong>202</strong> <code>data</code> = null (202): the run was accepted, not completed — read its outcome with /integration-run-status. <code>metadata</code> = apiVersion, operation, requestId, runId, integrationId, revision, status (\"accepted\", or the state of the run this runReference already holds).</p>\n<p><strong>Before sending:</strong> set <code>integrationName</code>, <code>integrationRunReference</code> (current values; the request is skipped until they are set), set <code>confirmMutating</code> = <code>yes</code>, send once. Development-test company only (<code>targetCompanyCode</code> = <code>COMP0002</code>, <code>financialYear</code> = <code>2026</code>); what it saves stays in BUSY.</p>\n<p><strong>Uncertain outcomes:</strong> after <code>504 WRITE_RESULT_UNKNOWN</code> / <code>BUSY_WRITE_UNCERTAIN</code> never resend blind: <code>cloudIdempotencyKey</code> is kept, so an accidental resend is refused <code>409</code>. Read Integration run status first. The same runReference never starts a second run: sending it again answers the run it already holds. <code>503 BUSY_COM_QUEUE_TIMEOUT</code> (nothing started) is the only retryable write error.</p>\n<p><strong>Route errors:</strong> 400 INTEGRATION_INVALID (company, four-digit year and a runReference of 1-200 characters; parameters an object; the input within 1 MiB); 413 INTEGRATION_LIMIT_EXCEEDED (the run's sealed snapshot exceeds the PC's storage limit; no run accepted), 503 INTEGRATION_UNAVAILABLE (no run accepted), 504 INTEGRATION_ACCEPTANCE_UNCONFIRMED (the PC could not confirm acceptance: submit the identical input with the same runReference, never a new one). Plus the shared write refusals (plan, BUSY COM, changed destination, settings, queue) in the operations reference.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","execute-integration"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"e16be9a2-3d54-9134-f5e5-2c872b6f0ea7"},{"name":"Integration run status (read only)","id":"effcdaa8-a840-20c4-95af-8e63518d6311","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"companyCode\": \"{{targetCompanyCode}}\",\n  \"financialYear\": \"{{financialYear}}\",\n  \"runId\": \"{{integrationRunId}}\"\n}","options":{"raw":{"language":"json"}}},"url":"{{cloudBaseUrl}}/v1/integration-run-status","description":"<p><strong>Cloud</strong> · <code>POST {{cloudBaseUrl}}/v1/integration-run-status</code> · Bearer <code>{{cloudApiToken}}</code> (organization token, not the Local API token) · operation <code>busy.integration-runs.get</code> · read only</p>\n<p><strong>Status:</strong> Deployed and live (release <code>790395a</code>, 2026-10-23). The PC must run an AI Zeny build that relays this operation; an older one answers <code>502 DEVICE_ERROR</code> (<code>details.deviceErrorCode</code> <code>REPORT_UNSUPPORTED</code>) and writes nothing.</p>\n<p><strong>Body</strong> (small; the PC also accepts at most 64 KiB per signed command): companyCode, financialYear, runId.</p>\n<p><strong>Answer:</strong> <code>{ success, data, metadata }</code> as the Local API answers it. <strong>200</strong> <code>data</code> = { run { id, integrationId, companyCode, financialYear, reference (the runReference), revision, status (\"accepted\" | \"running\" | \"awaiting\" | \"succeeded\" | \"partial\" | \"failed\" | \"interrupted\" | \"cancelled\" | \"needs_review\"), active, createdUtc, updatedUtc, stateVersion, origin }, items [ { intentId, generation, operation, key (the original external key), contentHash, result { state, jobId, data, metadata, error { code, message, field, details, status } }, noWriteProven } ], output, failure } — the PC's record; a script's own success value is not the run's outcome. <code>metadata</code> = apiVersion, operation, requestId.</p>\n<p><strong>Use:</strong> after <em>Execute customer integration</em> the test stores <code>integrationRunId</code>; send this to read the run. Safe to repeat.</p>\n<p><strong>Route errors:</strong> 400 INTEGRATION_INVALID (companyCode, financialYear and runId are required), 404 INTEGRATION_NOT_FOUND (no such run); 403 INTEGRATION_SCOPE_DENIED (the run belongs to another company or year, or its accepted read scope is wider than the years signed: send additionalFinancialYear with them); 409 INTEGRATION_REVIEW_REQUIRED (a terminal run or attempt has no protected proof: review it on the PC), 503 INTEGRATION_UNAVAILABLE. Plus the shared write refusals (plan, BUSY COM, changed destination, settings, queue) in the operations reference.</p>\n<p>Reference: docs/public-api/AI-Zeny-Cloud-API-V1-Operations.md and docs/integration/AI-Zeny-Cloud-Relay-Parity-Matrix-2026-10-23.md.</p>\n","urlObject":{"path":["v1","integration-run-status"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[],"_postman_id":"effcdaa8-a840-20c4-95af-8e63518d6311"}],"id":"9c202da1-8ec9-4cc9-90ca-bf623650a333","description":"<p><strong>Cloud Relay — live requests through the online Windows PC.</strong></p>\n<ul>\n<li><strong>Base URL:</strong> <code>{{cloudBaseUrl}}</code> (for example <code>https://api.aizeny.com</code>); routes begin <code>/v1/</code>.</li>\n<li><strong>Authentication:</strong> <code>Authorization: Bearer {{cloudApiToken}}</code>, the organization's cloud API token. Do not use the Local API token here.</li>\n<li><strong>Availability:</strong> the enrolled PC and Pusher connection must be online. The cloud forwards supported operations to the PC and returns its result. This is not the server-side SQLite Snapshot API.</li>\n<li><strong>Read versus write:</strong> folders labeled <em>(read only)</em> do not modify BUSY even when the method is POST. ⚠ folders can change BUSY data; their requests require the one-send <code>confirmMutating=yes</code> guard. Never automatically retry an uncertain write.</li>\n<li><strong>Supported operations:</strong> use the requests in this folder as the current cloud-route list. Master create/modify routes exist but require a compatible Windows agent; an older agent may refuse them. Sales-order creation, schedules, messages and PC settings have no Cloud Relay route here; use Local PC where supported.</li>\n<li><strong>For offline-PC accounting GETs:</strong> use the sibling <strong>Cloud Snapshot (server SQLite; PC may be offline)</strong> folder in this same collection. Snapshot data can be older than the latest PC books and reports its own freshness.</li>\n</ul>\n<p>Cloud Relay and Cloud Snapshot use the same <code>{{cloudBaseUrl}}</code> and <code>{{cloudApiToken}}</code>, but have different data sources and online-PC requirements. Both are distinct from direct Local PC requests.</p>\n","_postman_id":"9c202da1-8ec9-4cc9-90ca-bf623650a333","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Cloud Snapshot (server SQLite; PC may be offline)","item":[{"name":"Snapshot catalogue","item":[{"name":"Company-years with a snapshot","id":"0c2b8df0-fac6-4044-942f-2ce183fbc616","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/companies?page=1&pageSize=100","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/companies</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.companies.list</code></td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { companyCode, financialYear (four digits), publishedTableCount (tables available), missingTables[], complete (all tables available), newestPublishedAt, oldestReadStartedAt, readTimesKnown } — every company-year with at least one table available, within the token's company scope, sorted by company then year</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, source (\"snapshot\"), pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable)</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Lists what can be read now. Access depends only on the token, its company scope and the subscription: neither the PC's current settings nor the plan's company or year counts nor the data's age hide a company-year that has a snapshot.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n</tbody>\n</table>\n</div><p>Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/companies?page=1&amp;pageSize=100\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","companies"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>page number, a whole number from 1</p>\n","type":"text/plain"},"key":"page","value":"1"},{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"100"}],"variable":[]}},"response":[{"id":"4e106dd4-da85-e1e7-27e3-593534e585cf","name":"SYNTHETIC — 200 snapshot.companies.list (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/companies?page=1&pageSize=100","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","companies"],"query":[{"key":"page","value":"1"},{"key":"pageSize","value":"100"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.companies.list\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"0c2b8df0-fac6-4044-942f-2ce183fbc616"},{"name":"Snapshot status of one company-year","id":"a9ba42cf-18e1-4e70-a6da-bb26b658c143","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.status.get</code></td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>not paged</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ companyCode, financialYear, complete, setId, readTimesKnown, oldestReadStartedAt, newestReadStartedAt, readStartSkewMs, oldestReadStartAgeMs, oldestPublishedAt, newestPublishedAt, missingTables[], tables: [{ table, present, version, snapshotAt, publishedAt, databaseBytes }] } for every table a snapshot can contain</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, source (\"snapshot\"), elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>snapshotAt is when the PC began reading that table for this snapshot (may be null); publishedAt is when that version became available in AI Zeny. They are reported separately, and no single \"as of\" instant is claimed. Age is informational only and never refuses a request.</td>\n</tr>\n</tbody>\n</table>\n</div><p>Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"75cecaa8-6da6-e961-d185-bc9473c324bd","name":"SYNTHETIC — 200 snapshot.status.get (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"complete\": false,\n    \"setId\": \"8c6b37bc404a7a7b\",\n    \"readTimesKnown\": true,\n    \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n    \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n    \"readStartSkewMs\": 0,\n    \"oldestReadStartAgeMs\": 0,\n    \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n    \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n    \"missingTables\": [\n      \"MasterAddressInfo\",\n      \"MasterSupport\",\n      \"Folio1\",\n      \"Config\",\n      \"CheckList\",\n      \"BillingDet\",\n      \"Tran1\",\n      \"Tran2\",\n      \"Tran3\",\n      \"Tran4\",\n      \"Tran10\",\n      \"VchGSTSumItemWise\",\n      \"VchOtherInfo\",\n      \"Company\",\n      \"BusyUserLog\",\n      \"PrinterReps\",\n      \"ItemSerialNo\",\n      \"ItemDesc\",\n      \"OrgSalePurc\",\n      \"ItemParamDet\",\n      \"Help1\"\n    ],\n    \"tables\": [\n      {\n        \"table\": \"Master1\",\n        \"present\": true,\n        \"version\": \"synthetic-v1\",\n        \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n        \"publishedAt\": \"2026-05-10T10:00:00.000Z\",\n        \"databaseBytes\": 1024\n      },\n      {\n        \"table\": \"MasterAddressInfo\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"MasterSupport\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"Folio1\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"Config\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"CheckList\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"BillingDet\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"Tran1\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"Tran2\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"Tran3\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"Tran4\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"Tran10\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"VchGSTSumItemWise\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"VchOtherInfo\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"Company\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"BusyUserLog\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"PrinterReps\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"ItemSerialNo\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"ItemDesc\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"OrgSalePurc\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"ItemParamDet\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      },\n      {\n        \"table\": \"Help1\",\n        \"present\": false,\n        \"version\": null,\n        \"snapshotAt\": null,\n        \"publishedAt\": null,\n        \"databaseBytes\": null\n      }\n    ]\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.status.get\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"a9ba42cf-18e1-4e70-a6da-bb26b658c143"}],"id":"95f87c35-3283-4b8f-9c99-03f611518e0d","description":"<p>Which company-years have a snapshot, and which tables each one holds. Call these first.</p>\n<ul>\n<li><strong>Company-years with a snapshot</strong> — <code>GET /v1/snapshot/companies</code></li>\n<li><strong>Snapshot status of one company-year</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}</code></li>\n</ul>\n","_postman_id":"95f87c35-3283-4b8f-9c99-03f611518e0d","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Masters","item":[{"name":"Branches","id":"a8cf6f00-92c5-4b5f-b1a3-3ed567415ee8","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/branches?pageSize=100","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/branches</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.branches.list</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/branches</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { branch_id, branch_name }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, source, snapshot { setId, tables[], readTimesKnown, … }, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Paged here (the twin answers every row): page ≥ 1, pageSize 1–500 (default 100), totalRows exact. Ordered by name (binary; NULL and empty first), then code, as the twin.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/branches?pageSize=100\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","branches"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"100"}],"variable":[]}},"response":[{"id":"d58879f6-6cc1-f2e5-e2bc-190e696ff052","name":"SYNTHETIC — 200 snapshot.branches.list (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/branches?pageSize=100","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","branches"],"query":[{"key":"pageSize","value":"100"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.branches.list\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"8c6b37bc404a7a7b\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"a8cf6f00-92c5-4b5f-b1a3-3ed567415ee8"},{"name":"Categories","id":"bab36161-390a-41de-908f-b2432c573106","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/categories?pageSize=100","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/categories</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.categories.list</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/categories</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { category_id, category_name }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, source, snapshot { setId, tables[], readTimesKnown, … }, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Paged here (the twin answers every row): page ≥ 1, pageSize 1–500 (default 100), totalRows exact. Ordered by name (binary; NULL and empty first), then code, as the twin.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/categories?pageSize=100\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","categories"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"100"}],"variable":[]}},"response":[{"id":"1de81a73-3ea3-7585-a554-1b0ef77b8152","name":"SYNTHETIC — 200 snapshot.categories.list (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/categories?pageSize=100","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","categories"],"query":[{"key":"pageSize","value":"100"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.categories.list\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"8c6b37bc404a7a7b\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"bab36161-390a-41de-908f-b2432c573106"},{"name":"Material centres","id":"5db6ddc1-5bc2-49f9-8245-0db05e3d07c1","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/material-centers?pageSize=100","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/material-centers</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.material-centers.list</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/material-centers</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { mc_id, mc_name, mc_alias, mc_print_name }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, source, snapshot { setId, tables[], readTimesKnown, … }, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Paged here (the twin answers every row): page ≥ 1, pageSize 1–500 (default 100), totalRows exact. Ordered by name (binary; NULL and empty first), then code, as the twin.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/material-centers?pageSize=100\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","material-centers"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"100"}],"variable":[]}},"response":[{"id":"68a42f80-e84c-2335-9384-8888ce291c16","name":"SYNTHETIC — 200 snapshot.material-centers.list (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/material-centers?pageSize=100","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","material-centers"],"query":[{"key":"pageSize","value":"100"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.material-centers.list\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"8c6b37bc404a7a7b\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"5db6ddc1-5bc2-49f9-8245-0db05e3d07c1"},{"name":"Salesmen","id":"24663a8b-30ec-4b43-9cca-a784fcb91e22","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/salesmen?pageSize=100","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/salesmen</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.salesmen.list</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/salesmen</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { salesman_id, salesman_name, salesman_alias, mobile_number, whatsapp_number, email } (a missing alias or contact detail is \"\")</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, source, snapshot { setId, tables[], readTimesKnown, … }, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Paged here (the twin answers every row): page ≥ 1, pageSize 1–500 (default 100), totalRows exact. Ordered by name (binary; NULL and empty first), then code, as the twin. As the twin, a salesman with two address rows appears twice (LEFT JOIN); those rows keep the address rows' stored order.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/salesmen?pageSize=100\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","salesmen"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"100"}],"variable":[]}},"response":[{"id":"f3b453ef-3434-4b94-3ebf-9967a50d50a9","name":"SYNTHETIC — 200 snapshot.salesmen.list (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/salesmen?pageSize=100","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","salesmen"],"query":[{"key":"pageSize","value":"100"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.salesmen.list\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"82a9e2808b0ff526\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"24663a8b-30ec-4b43-9cca-a784fcb91e22"},{"name":"Sale types","id":"4fa63646-692f-4d6d-a8a2-6c8f910db666","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sale-types?pageSize=100","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/sale-types</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.sale-types.list</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/sale-types</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { sale_type_id, sale_type_name, sale_type_alias, sale_type_print_name }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, source, snapshot { setId, tables[], readTimesKnown, … }, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Paged here (the twin answers every row): page ≥ 1, pageSize 1–500 (default 100), totalRows exact. Ordered by name (binary; NULL and empty first), then code, as the twin.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/sale-types?pageSize=100\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","sale-types"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"100"}],"variable":[]}},"response":[{"id":"ef096ee1-d963-2dc2-2365-6fb52b4446e3","name":"SYNTHETIC — 200 snapshot.sale-types.list (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sale-types?pageSize=100","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","sale-types"],"query":[{"key":"pageSize","value":"100"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.sale-types.list\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"8c6b37bc404a7a7b\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"4fa63646-692f-4d6d-a8a2-6c8f910db666"},{"name":"Voucher series","id":"655dc0b5-35c0-4fc5-8514-8dd2706464d8","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/voucher-series?pageSize=100","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/voucher-series</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.voucher-series.list</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/voucher-series</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { voucher_series_id, voucher_series_name } (a missing name is \"\")</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, source, snapshot { setId, tables[], readTimesKnown, … }, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Paged here (the twin answers every row): page ≥ 1, pageSize 1–500 (default 100), totalRows exact. Ordered by name (binary; NULL and empty first), then code, as the twin. MasterType 21 with I1 = 12, as the twin.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/voucher-series?pageSize=100\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","voucher-series"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"100"}],"variable":[]}},"response":[{"id":"9c162d56-0138-e48e-6917-0bd064fc0e15","name":"SYNTHETIC — 200 snapshot.voucher-series.list (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/voucher-series?pageSize=100","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","voucher-series"],"query":[{"key":"pageSize","value":"100"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.voucher-series.list\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"8c6b37bc404a7a7b\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"655dc0b5-35c0-4fc5-8514-8dd2706464d8"},{"name":"Item parameters","id":"65adf108-4cd6-488e-9f9e-b0d9f507db57","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/parameters?pageSize=100","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/parameters</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.parameters.list</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/parameters</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { id, name } (id = the name's position from 1 in binary name order)</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, source, snapshot { setId, tables[], readTimesKnown, … }, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Paged here (the twin answers every row); totalRows exact. Distinct ItemParamDet.C1 values with spaces trimmed, blank names left out, compared and ordered in binary. id follows the twin (position in name order); ItemParamDet has no index, so the read is a full scan of a small table.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/parameters?pageSize=100\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","parameters"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"100"}],"variable":[]}},"response":[{"id":"9c6b1f89-dae5-a221-3dc3-906d041d6597","name":"SYNTHETIC — 200 snapshot.parameters.list (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/parameters?pageSize=100","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","parameters"],"query":[{"key":"pageSize","value":"100"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.parameters.list\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"42ceb177ef0ea3ac\",\n      \"tables\": [\n        {\n          \"table\": \"ItemParamDet\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"65adf108-4cd6-488e-9f9e-b0d9f507db57"},{"name":"Product groups","id":"2129a5d3-4168-4303-873a-8e998447ee46","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/product-groups?page=1&pageSize=200","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/product-groups</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.product-groups.list</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/product-groups</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { product_group_id, product_group_name }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, source, snapshot { setId, tables[], readTimesKnown, … }, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Paged here (the twin answers every row): page ≥ 1, pageSize 1–500 (default 100), totalRows exact. Ordered by name (binary; NULL and empty first), then code, as the twin.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/product-groups?page=1&amp;pageSize=200\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","product-groups"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>page number, a whole number from 1</p>\n","type":"text/plain"},"key":"page","value":"1"},{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"200"}],"variable":[]}},"response":[{"id":"74702c2e-68a2-483a-c37c-67addc191c01","name":"SYNTHETIC — 200 snapshot.product-groups.list (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/product-groups?page=1&pageSize=200","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","product-groups"],"query":[{"key":"page","value":"1"},{"key":"pageSize","value":"200"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.product-groups.list\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"8c6b37bc404a7a7b\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"2129a5d3-4168-4303-873a-8e998447ee46"}],"id":"393084a1-b114-491c-bc2d-681f7e9bff49","description":"<p>Snapshot reads of the reports in the live family <em>Masters</em> (8); each request names its live equivalent.</p>\n<ul>\n<li><strong>Branches</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/branches</code></li>\n<li><strong>Categories</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/categories</code></li>\n<li><strong>Material centres</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/material-centers</code></li>\n<li><strong>Salesmen</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/salesmen</code></li>\n<li><strong>Sale types</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/sale-types</code></li>\n<li><strong>Voucher series</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/voucher-series</code></li>\n<li><strong>Item parameters</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/parameters</code></li>\n<li><strong>Product groups</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/product-groups</code></li>\n</ul>\n","_postman_id":"393084a1-b114-491c-bc2d-681f7e9bff49","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Products","item":[{"name":"Product optional fields","id":"b1515c33-f874-411e-80ac-05ec101e1b92","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/product-optional-fields","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/product-optional-fields</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.product-optional-fields.list</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/products-of-config</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>not paged</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { field_no, of_column, field_name, field_type, decimal_places, maintain_master_database } (at most 10 rows)</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, source, snapshot, filters, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Unpaged (at most ten fields). The first Config row with RecType 2 / Type 6 names the fields and the first with RecType 79 / Type 6 types them, in stored order; without either row the answer is empty, as the twin. Field types: 1 Text, 2 List, 3 Amount, 4 Quantity, 5 Numeric (decimal_places), 6 Date, 7 Yes/No; maintain_master_database Y/N for Text. Config has no usable index on real data (scan of a small table).</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/product-optional-fields\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","product-optional-fields"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"4d15cdc5-c20d-83b9-5efc-e064a68875f2","name":"SYNTHETIC — 200 snapshot.product-optional-fields.list (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/product-optional-fields"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.product-optional-fields.list\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"e8a728f5a0e8a2cf\",\n      \"tables\": [\n        {\n          \"table\": \"Config\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"b1515c33-f874-411e-80ac-05ec101e1b92"},{"name":"Products","id":"d915df83-1765-4696-8d26-a31da50fbffa","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/products?inStockOnly=true&priceCategory=1&pageSize=100","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/products</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.products.page</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/products-pagination</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { product_id, product_name, product_alias, product_print_name, product_sales_price, product_purchase_price, product_mrp, product_group_name, product_group_id, product_unit, product_unit_code, product_alternative_unit, product_alternative_unit_code, product_alternative_unit_conversion_factor, product_alternative_unit_price, product_mc_name, product_mc_code, product_tax_name, product_tax_id, product_hsn_code, product_tax_rate, product_stock, product_price, product_sales_discount, product_sales_markup, product_purchase_discount, product_description_line1…4, product_alias_1…15, product_created_by, product_creation_time, product_modified_by, product_modification_time, parameters (parametersStock), optional_fields (optionalFields), erp_categories (erpCategories) }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, appliedFilters, source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 SNAPSHOT_SCHEMA_UNSUPPORTED (a product without a code); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>The twin's /products-pagination (the unpaged /products is merged here: the snapshot surface has no unpaged product list). Switches as the twin: materialCenterIds (comma-separated, unique, positive; at most 100 here) counts only those centres (Tran2 record type 2 and Tran4.D1) and rounds the stock; includePendingSalesOrder subtracts the rounded pending sales-order quantity (Tran3 record type 4, method 1, voucher type 12 or 1/−1200) and rounds; parametersStock / optionalFields / erpCategories add their member and round the stock; priceCategory (1–26) takes sales price, MRP and discount from MasterSupport I1 = 100 + category (largest D1/D3/D2, NULL as 0) when the product has a row. product_stock = SUM(Tran2.Value1) over every voucher type but 12, 25, 26, 13 + SUM(Folio1.D1), not rounded without a switch. inStockOnly keeps products whose stock is above 0 (and above 0 once rounded with a detail switch) and is applied BEFORE the page is cut, so totalRows is exact (the twin and the reference filtered after building the page). Paged here with page/pageSize (the twin requires both and has no maximum; this surface caps pageSize at 500); totalRows counts distinct products (one per code and name), and a page holds every row of its products — several when BUSY holds several address or joined master rows for a product and no detail switch is set (one with a switch), as the twin. Ordered by name (binary), then code. product_creation_time / product_modification_time are written as the twin documents them (yyyy-MM-ddTHH:mm:ss[.ffffff]) from BUSY's stored date and time. metadata.appliedFilters echoes the switches with defaults filled in (the twin's metadata.filters); metadata.filters lists the members sent.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>materialCenterIds</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>comma-separated, unique positive whole numbers, at most 100: the material centres whose stock is reported</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>includePendingSalesOrder</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): subtract the pending sales-order quantity from the stock shown</td>\n<td>false</td>\n</tr>\n<tr>\n<td><code>inStockOnly</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): only products with stock (decided before paging, so totals stay exact)</td>\n<td>false</td>\n</tr>\n<tr>\n<td><code>parametersStock</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): add stock by item parameter</td>\n<td>false</td>\n</tr>\n<tr>\n<td><code>optionalFields</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): add the product's optional fields</td>\n<td>false</td>\n</tr>\n<tr>\n<td><code>erpCategories</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): add the ERP category fields</td>\n<td>false</td>\n</tr>\n<tr>\n<td><code>priceCategory</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>one whole number from 1 to 26: the price category reported as the price</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/products?inStockOnly=true&amp;priceCategory=1&amp;pageSize=100\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","products"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>true or false (exactly; any other text is refused): only products with stock (decided before paging, so totals stay exact)</p>\n","type":"text/plain"},"key":"inStockOnly","value":"true"},{"description":{"content":"<p>one whole number from 1 to 26: the price category reported as the price</p>\n","type":"text/plain"},"key":"priceCategory","value":"1"},{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"100"}],"variable":[]}},"response":[{"id":"a7a7c127-59ca-2476-c7d5-7ac0f07b819b","name":"SYNTHETIC — 200 snapshot.products.page (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/products?inStockOnly=true&priceCategory=1&pageSize=100","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","products"],"query":[{"key":"inStockOnly","value":"true"},{"key":"priceCategory","value":"1"},{"key":"pageSize","value":"100"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.products.page\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"eb5b723d5fd7f75d\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"d915df83-1765-4696-8d26-a31da50fbffa"},{"name":"Product search","id":"7f4a3a8c-200f-4c94-880c-5b17fa975d58","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/products/search?name=bolt&pageSize=50","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/products/search</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.products.search</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/products-search</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { product_id, product_name, product_alias, product_print_name, product_sales_price, product_purchase_price, product_mrp, product_group_name, product_group_id, product_unit, product_unit_code, product_alternative_unit, product_alternative_unit_code, product_alternative_unit_conversion_factor, product_alternative_unit_price, product_mc_name, product_mc_code, product_tax_name, product_tax_id, product_hsn_code, product_tax_rate, product_stock, product_price, product_sales_discount, product_sales_markup, product_purchase_discount, product_description_line1…4, product_alias_1…15, product_created_by, product_creation_time, product_modified_by, product_modification_time, parameters (parametersStock), optional_fields (optionalFields), erp_categories (erpCategories) }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, appliedFilters (with search), source, snapshot, filters (never a search term), pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 SNAPSHOT_SCHEMA_UNSUPPORTED (a product without a code); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Search fields as the twin, combined with AND: name, printName, alias (contained in Name, PrintName, Alias), multipleAlias (contained in any MasterSupport.C1 with I1 201–215), groupName (contained in the group master's name), groupId (equals ParentGrp, a positive whole number). \"Contained\" is SQLite's LOWER(COALESCE(x, '')) LIKE LOWER('%term%') with the term bound: ASCII letters case-insensitive; % and _ in a term are wildcards (neither twin nor reference escapes them). The reference's colon-keyed parameters did not bind and returned no rows; the twin and this surface bind them. No search field returns every product (the twin's rule). A blank term is invalid here (the twin treats it as no filter), and so is a term containing a NUL character (SQLite's LIKE would stop at it and match a different set). Terms are never echoed in metadata.filters or logged (appliedFilters.search shows them to the caller only). Paged (the twin is unpaged). Switches as the twin: materialCenterIds (comma-separated, unique, positive; at most 100 here) counts only those centres (Tran2 record type 2 and Tran4.D1) and rounds the stock; includePendingSalesOrder subtracts the rounded pending sales-order quantity (Tran3 record type 4, method 1, voucher type 12 or 1/−1200) and rounds; parametersStock / optionalFields / erpCategories add their member and round the stock; priceCategory (1–26) takes sales price, MRP and discount from MasterSupport I1 = 100 + category (largest D1/D3/D2, NULL as 0) when the product has a row. product_stock = SUM(Tran2.Value1) over every voucher type but 12, 25, 26, 13 + SUM(Folio1.D1), not rounded without a switch. inStockOnly keeps products whose stock is above 0 (and above 0 once rounded with a detail switch) and is applied BEFORE the page is cut, so totalRows is exact (the twin and the reference filtered after building the page). Paged here with page/pageSize (the twin requires both and has no maximum; this surface caps pageSize at 500); totalRows counts distinct products (one per code and name), and a page holds every row of its products — several when BUSY holds several address or joined master rows for a product and no detail switch is set (one with a switch), as the twin. Ordered by name (binary), then code. product_creation_time / product_modification_time are written as the twin documents them (yyyy-MM-ddTHH:mm:ss[.ffffff]) from BUSY's stored date and time. metadata.appliedFilters echoes the switches with defaults filled in (the twin's metadata.filters); metadata.filters lists the members sent.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>name</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>search term for the product name: trimmed, not blank, no NUL character; matched with SQL LIKE, so % and _ act as wildcards; never echoed in the answer or logged</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>printName</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>search term for the print name (same rules as name); never echoed in the answer or logged</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>alias</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>search term for the alias (same rules as name); never echoed in the answer or logged</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>multipleAlias</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>search term for the additional aliases (same rules as name); never echoed in the answer or logged</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>groupId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>a positive whole number (up to 9223372036854775807): the product group</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>groupName</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>search term for the product group name (same rules as name); never echoed in the answer or logged</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>materialCenterIds</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>comma-separated, unique positive whole numbers, at most 100: the material centres whose stock is reported</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>includePendingSalesOrder</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): subtract the pending sales-order quantity from the stock shown</td>\n<td>false</td>\n</tr>\n<tr>\n<td><code>inStockOnly</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): only products with stock (decided before paging, so totals stay exact)</td>\n<td>false</td>\n</tr>\n<tr>\n<td><code>parametersStock</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): add stock by item parameter</td>\n<td>false</td>\n</tr>\n<tr>\n<td><code>optionalFields</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): add the product's optional fields</td>\n<td>false</td>\n</tr>\n<tr>\n<td><code>erpCategories</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): add the ERP category fields</td>\n<td>false</td>\n</tr>\n<tr>\n<td><code>priceCategory</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>one whole number from 1 to 26: the price category reported as the price</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/products/search?name=bolt&amp;pageSize=50\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","products","search"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>search term for the product name: trimmed, not blank, no NUL character; matched with SQL LIKE, so % and _ act as wildcards; never echoed in the answer or logged</p>\n","type":"text/plain"},"key":"name","value":"bolt"},{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"50"}],"variable":[]}},"response":[{"id":"9ab0945f-a987-1dd6-fec6-d7cfea64f0f1","name":"SYNTHETIC — 200 snapshot.products.search (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/products/search?name=bolt&pageSize=50","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","products","search"],"query":[{"key":"name","value":"bolt"},{"key":"pageSize","value":"50"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.products.search\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"8c6b37bc404a7a7b\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"7f4a3a8c-200f-4c94-880c-5b17fa975d58"}],"id":"982a097a-c362-4896-a517-d2e114908eda","description":"<p>Snapshot reads of the reports in the live family <em>Products</em> (3); each request names its live equivalent.</p>\n<ul>\n<li><strong>Product optional fields</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/product-optional-fields</code></li>\n<li><strong>Products</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/products</code></li>\n<li><strong>Product search</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/products/search</code></li>\n</ul>\n","_postman_id":"982a097a-c362-4896-a517-d2e114908eda","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Pricing and hierarchies","item":[{"name":"Customer group hierarchy","id":"f822ce07-771e-4943-90c1-0c4e3b745dff","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customer-groups/hierarchy?rootGroupId={{customerGroupId}}","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/customer-groups/hierarchy</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.customer-groups.hierarchy</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/customer-groups-hierarchy</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>not paged</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ root_group_id, hierarchy: [ { group_id, group_name, parent_group_id, direct_customer_count, children, descendant_group_ids, total_customer_count } ] }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, source, snapshot, filters { rootGroupId }, groupCount, rootCount, rowCount, maxDepth, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 NOT_FOUND (field rootGroupId); 422 BUSY_GROUP_HIERARCHY_INVALID (cycle, repeated code, more than 500 levels); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Unpaged, as the twin (bounded by the customer group count and the 2 MiB response limit; send rootGroupId for one subtree). rootGroupId is a positive 64-bit whole number, as the twin.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>rootGroupId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>a positive whole number (up to 9223372036854775807): the group whose sub-tree is returned</td>\n<td>the whole hierarchy</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/customer-groups/hierarchy?rootGroupId=116\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customer-groups","hierarchy"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a positive whole number (up to 9223372036854775807): the group whose sub-tree is returned</p>\n","type":"text/plain"},"key":"rootGroupId","value":"{{customerGroupId}}"}],"variable":[]}},"response":[{"id":"20ece4fb-d35a-2d3f-8125-3a7f6822f27a","name":"SYNTHETIC — 200 snapshot.customer-groups.hierarchy (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customer-groups/hierarchy?rootGroupId={{customerGroupId}}","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customer-groups","hierarchy"],"query":[{"key":"rootGroupId","value":"{{customerGroupId}}"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"root_group_id\": null,\n    \"hierarchy\": []\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.customer-groups.hierarchy\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"8c6b37bc404a7a7b\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"f822ce07-771e-4943-90c1-0c4e3b745dff"},{"name":"Product group hierarchy","id":"569e2632-19b1-4363-ac2e-2624f8e23f40","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/product-groups/hierarchy","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/product-groups/hierarchy</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.product-groups.hierarchy</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/product-groups-hierarchy</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>not paged</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ root_group_id, hierarchy: [ { group_id, group_name, parent_group_id, direct_product_count, children, descendant_group_ids, total_product_count } ] }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, source, snapshot, filters { rootGroupId }, groupCount, rootCount, rowCount, maxDepth, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 NOT_FOUND (field rootGroupId); 422 BUSY_GROUP_HIERARCHY_INVALID (cycle, repeated code, more than 500 levels); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Unpaged, as the twin (bounded by the product group count and the 2 MiB response limit; send rootGroupId for one subtree). rootGroupId is a positive 64-bit whole number, as the twin.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>rootGroupId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>a positive whole number (up to 9223372036854775807): the group whose sub-tree is returned</td>\n<td>the whole hierarchy</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/product-groups/hierarchy\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","product-groups","hierarchy"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"359a19ff-7fbb-0040-3bb2-556373ac516a","name":"SYNTHETIC — 200 snapshot.product-groups.hierarchy (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/product-groups/hierarchy"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"root_group_id\": null,\n    \"hierarchy\": []\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.product-groups.hierarchy\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"8c6b37bc404a7a7b\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"569e2632-19b1-4363-ac2e-2624f8e23f40"},{"name":"Product category prices","id":"759803c5-ca5d-4b9a-bff0-476c5a07de94","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/products/price-categories?priceCategories=1,2,3","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/products/price-categories</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.products.price-categories</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/products-multiple-prices</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { product_id, product_name, then per category N (prefix a–z = 1–26): {p}_product_sales_price, {p}_product_mrp, {p}_product_sales_discount }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, source, snapshot, filters, pagination, priceCategories, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 SNAPSHOT_SCHEMA_UNSUPPORTED (a product without a code); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>priceCategories: comma-separated unique whole numbers 1–26, default 1–10, applied in ascending order and echoed as metadata.priceCategories. Every product (MasterType 6), by name (binary) then code; per category N the largest COALESCE(D1, 0), COALESCE(D3, 0), COALESCE(D2, 0) of the product's MasterSupport rows with I1 = 100 + N, or all three null when it has none (the reference's LEFT JOIN). Numbers unrounded. Paged by product (the twin is unpaged).</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>priceCategories</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>comma-separated, unique whole numbers from 1 to 26, applied in ascending order</td>\n<td>1,2,3,4,5,6,7,8,9,10</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/products/price-categories?priceCategories=1,2,3\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","products","price-categories"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>comma-separated, unique whole numbers from 1 to 26, applied in ascending order</p>\n","type":"text/plain"},"key":"priceCategories","value":"1,2,3"}],"variable":[]}},"response":[{"id":"36ddba52-e2dd-a9f9-bea1-5a5c994346a0","name":"SYNTHETIC — 200 snapshot.products.price-categories (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/products/price-categories?priceCategories=1,2,3","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","products","price-categories"],"query":[{"key":"priceCategories","value":"1,2,3"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.products.price-categories\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"2a9275f8ac1dae75\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterSupport\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"759803c5-ca5d-4b9a-bff0-476c5a07de94"},{"name":"Product date-wise prices","id":"191b7d80-5935-4450-88c6-e7b38216ef14","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/products/date-wise-prices?pageSize=100","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/products/date-wise-prices</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.products.date-wise-prices</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/products-multiple-prices-datewise</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { product_id, product_name, latest_pricing_date, then per identifier at that date (prefix a, b … z, aa …): {p}_price_identifier, {p}_product_sales_price, {p}_product_mrp, {p}_product_sales_discount }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, source, snapshot, filters, pagination, latestPricingDate, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 SNAPSHOT_SCHEMA_UNSUPPORTED (a product without a code); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>The products with date-wise rows (MasterSupport I2 = 9, a Date, an I1 not blank once trimmed), by name (binary) then code. Per product: latest_pricing_date (its latest Date, written as the twin documents it, yyyy-MM-ddTHH:mm:ss[.ffffff], from BUSY's stored date and time), then for that date's rows grouped by identifier (I1, spaces trimmed), ordered by the identifier as a SQLite integer then as text, the largest COALESCE(D1/D3/D2, 0). metadata.latestPricingDate is the date every product with history shares (over all of them, not the page), else null. A row's members vary with its identifiers. Paged by product (the twin is unpaged).</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/products/date-wise-prices?pageSize=100\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","products","date-wise-prices"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"100"}],"variable":[]}},"response":[{"id":"1d28c405-b289-3bc5-893e-b9af7c3b421b","name":"SYNTHETIC — 200 snapshot.products.date-wise-prices (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/products/date-wise-prices?pageSize=100","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","products","date-wise-prices"],"query":[{"key":"pageSize","value":"100"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.products.date-wise-prices\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"2a9275f8ac1dae75\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterSupport\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"191b7d80-5935-4450-88c6-e7b38216ef14"}],"id":"c21b7e02-72c4-4000-b432-98e849eb6cfa","description":"<p>Snapshot reads of the reports in the live family <em>Pricing and hierarchies</em> (4); each request names its live equivalent.</p>\n<ul>\n<li><strong>Customer group hierarchy</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/customer-groups/hierarchy</code></li>\n<li><strong>Product group hierarchy</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/product-groups/hierarchy</code></li>\n<li><strong>Product category prices</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/products/price-categories</code></li>\n<li><strong>Product date-wise prices</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/products/date-wise-prices</code></li>\n</ul>\n","_postman_id":"c21b7e02-72c4-4000-b432-98e849eb6cfa","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Customers","item":[{"name":"Customers","id":"d5a676e6-e28f-42af-9255-5e1b10af63a5","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers?pendingSalesOrderOnly=false&pageSize=100","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/customers</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.customers.list</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/customers</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { customer_id, customer_name, customer_alias, group_id, group_name, mobile_number, email_id, whatsapp_number, address_line_1…4, pin_code, country, state, gst_number, pan_number, station, opening_balance, balance, closing_balance, salesman_id, salesman_name, salesman_mobile_number, salesman_whatsapp_number, price_category }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, pendingSalesOrderOnly, source, snapshot, filters, pagination, rowCount, customerCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Paged (the twin is unpaged); a customer with several address, opening or salesman-address rows appears once per combination, as the twin. closing_balance = Folio1.D1 + SUM(Tran2.Value1) over every Tran2 row of the customer (no record-type test, as twin and reference), each rounded to 2 decimals on the exact binary value. pendingSalesOrderOnly is the twin's member. whatsappNumber and email are the folded /validate-whatsapp and /validate-email look-ups (the twin's normalization): they keep only the customer rows built from a matching address row, and are never echoed in metadata or logged. groupId (direct group, Master1.ParentGrp), salesmanId (Master1.CM3) and search (Name or Alias, case-insensitive substring) are snapshot-surface filters with no twin member. Rows of one customer are ordered by their JSON text, as the twin (JavaScript string escaping).</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>pendingSalesOrderOnly</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): only customers with a pending sales order</td>\n<td>false</td>\n</tr>\n<tr>\n<td><code>groupId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the customer group</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>salesmanId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the salesman</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>search</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>1 to 200 characters after trimming, matched as a literal part of the name; never echoed in the answer or logged</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>whatsappNumber</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>a phone number; spaces, (, ), + and - are removed, then 1 to 255 characters must remain; never echoed in the answer or logged</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>email</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>an e-mail address (<a href=\"mailto:name@domain.tld\">name@domain.tld</a>, no spaces, at most 255 characters), trimmed and lower-cased; never echoed in the answer or logged</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/customers?pendingSalesOrderOnly=false&amp;pageSize=100\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>true or false (exactly; any other text is refused): only customers with a pending sales order</p>\n","type":"text/plain"},"key":"pendingSalesOrderOnly","value":"false"},{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"100"}],"variable":[]}},"response":[{"id":"8a33470a-1032-cb36-a677-ad95eaafae8a","name":"SYNTHETIC — 200 snapshot.customers.list (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers?pendingSalesOrderOnly=false&pageSize=100","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers"],"query":[{"key":"pendingSalesOrderOnly","value":"false"},{"key":"pageSize","value":"100"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.customers.list\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"55b5a2548403b771\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Folio1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"d5a676e6-e28f-42af-9255-5e1b10af63a5"},{"name":"One customer","id":"c7fca2f3-8522-4be3-99d3-cccced67227d","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/{{customerId}}","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/customers/{customerId}</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.customers.get</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/customer</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>path: customerId</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>not paged</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>one-element array of { customer_id, customer_name, customer_alias, group_id, group_name, mobile_number, email_id, whatsapp_number, address_line_1…4, pin_code, country, state, gst_number, pan_number, station, opening_balance, balance, closing_balance, salesman_id, salesman_name, salesman_mobile_number, salesman_whatsapp_number, price_category }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, customerId, source, snapshot, filters, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 NOT_FOUND (field customerId); 422 BUSY_DATA_INCONSISTENT (more than one address or opening row); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>The twin's one customer: the same row as the list, refused with 422 when the customer has more than one row (several address, opening or salesman-address rows).</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>customerId</code></td>\n<td>path</td>\n<td>integer</td>\n<td>yes</td>\n<td>whole number from 1 to 2147483647: the customer's code</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/customers/1001\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","{{customerId}}"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"91a4fa0d-9ae8-1a5f-fb5d-0d11d77c20b1","name":"SYNTHETIC — 200 snapshot.customers.get (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/{{customerId}}"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [\n    {\n      \"customer_id\": 1,\n      \"customer_name\": \"Synthetic Customer\",\n      \"customer_alias\": \"\",\n      \"group_id\": 1,\n      \"group_name\": \"Synthetic Group\",\n      \"mobile_number\": \"\",\n      \"email_id\": \"\",\n      \"whatsapp_number\": \"\",\n      \"pin_code\": \"\",\n      \"country\": \"\",\n      \"state\": \"\",\n      \"gst_number\": \"\",\n      \"pan_number\": \"\",\n      \"station\": \"\",\n      \"opening_balance\": 0,\n      \"balance\": 0,\n      \"closing_balance\": 0,\n      \"salesman_id\": 0,\n      \"salesman_name\": \"Synthetic salesman_name\",\n      \"salesman_mobile_number\": \"Synthetic salesman_mobile_number\",\n      \"salesman_whatsapp_number\": \"Synthetic salesman_whatsapp_number\",\n      \"price_category\": 0,\n      \"address_line_1\": \"\",\n      \"address_line_2\": \"\",\n      \"address_line_3\": \"\",\n      \"address_line_4\": \"\"\n    }\n  ],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.customers.get\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"55b5a2548403b771\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Folio1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"rowCount\": 1,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"c7fca2f3-8522-4be3-99d3-cccced67227d"}],"id":"b8f090f0-2949-406f-9059-39f03b32d690","description":"<p>Snapshot reads of the reports in the live family <em>Customers</em> (2); each request names its live equivalent.</p>\n<ul>\n<li><strong>Customers</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/customers</code></li>\n<li><strong>One customer</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/customers/{customerId}</code></li>\n</ul>\n","_postman_id":"b8f090f0-2949-406f-9059-39f03b32d690","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Customer and supplier accounting","item":[{"name":"Customers with pending bills","id":"ebdd37fb-612f-4e5a-b894-34b4ce14f618","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/pending-bills?asOnDate={{financialYear}}-10-31&pageSize=100","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/customers/pending-bills</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.customers.pending-bills</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/customers-pending-bills</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>asOnDate</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { customer_id, customer_name, customer_alias, group_id, group_name, mobile_number, email_id, whatsapp_number, address_line_1…4, pin_code, country, state, gst_number, pan_number, station, opening_balance, balance, closing_balance, salesman_id, salesman_name, salesman_mobile_number, salesman_whatsapp_number, price_category, total_pending_amount, total_due_amount }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, calculationDate, source, snapshot, filters { asOnDate, withWhatsAppOnly }, pagination, rowCount, customerCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>asOnDate is required (the twin uses the PC's UTC date) and decides which bills are due (DATE(DueDate) on or before it). Totals are over every eligible bill (method 1, record type 1; opening/sale debits, return/journal credits) whose rounded pending amount is not 0, keyed by the resolved customer (voucher header party, else the journal's representative line, else the trace). withWhatsAppOnly (default true) keeps the twin's rule — only customer rows with a non-blank WhatsApp number; false lists every row of a customer with totals. Paged (the twin is unpaged); ordered as the customer list.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>asOnDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>yes</td>\n<td>a real calendar date written YYYY-MM-DD, inside the financial year (1 April to 31 March): the day the answer is calculated for. Never taken from a clock</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>withWhatsAppOnly</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): only customer rows with a WhatsApp number (false lists every row of a customer)</td>\n<td>true</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/customers/pending-bills?asOnDate=2025-10-31&amp;pageSize=100\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","pending-bills"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD, inside the financial year (1 April to 31 March): the day the answer is calculated for. Never taken from a clock</p>\n","type":"text/plain"},"key":"asOnDate","value":"{{financialYear}}-10-31"},{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"100"}],"variable":[]}},"response":[{"id":"367af71d-ba85-63d5-fba2-cd9c5ed6f635","name":"SYNTHETIC — 200 snapshot.customers.pending-bills (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/pending-bills?asOnDate={{financialYear}}-10-31&pageSize=100","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","pending-bills"],"query":[{"key":"asOnDate","value":"{{financialYear}}-10-31"},{"key":"pageSize","value":"100"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.customers.pending-bills\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"07d5d1d8ffcb868f\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Folio1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran3\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"ebdd37fb-612f-4e5a-b894-34b4ce14f618"},{"name":"Customer dashboard","id":"511e78d3-98b2-426c-9d2c-61f1bb9d2ced","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/{{customerId}}/dashboard?asOnDate={{financialYear}}-10-31","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/customers/{customerId}/dashboard</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.customers.dashboard</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/customer-dashboard</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>path: customerId; asOnDate</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>not paged</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ customer_id, customer_name, customer_print_name, closing_balance, pending_balance, due_balance, credit_limit, total_sales_amount, total_receipts_amount, total_sale_returns_amount }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, customerId, calculationDate, source, snapshot, filters { asOnDate }, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 NOT_FOUND (field customerId); 422 BUSY_DATA_INCONSISTENT (the code is repeated); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>asOnDate is required (the twin uses the PC's UTC date) and decides due_balance. closing_balance = ROUND2(ROUND2(Σ Folio1.D1) + ROUND2(Σ Tran2.Value1)) as the twin; pending/due as the customers-with-pending-bills totals; credit_limit = Master1.D1; sales (9) and sale returns (3) = Σ |VchSalePurcAmt ?? VchAmtBaseCur| in ascending order; receipts = Σ of each receipt voucher's largest |CashFlow ?? Value1| line of the customer.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>customerId</code></td>\n<td>path</td>\n<td>integer</td>\n<td>yes</td>\n<td>whole number from 1 to 2147483647: the customer's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>asOnDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>yes</td>\n<td>a real calendar date written YYYY-MM-DD, inside the financial year (1 April to 31 March): the day the answer is calculated for. Never taken from a clock</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/customers/1001/dashboard?asOnDate=2025-10-31\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","{{customerId}}","dashboard"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD, inside the financial year (1 April to 31 March): the day the answer is calculated for. Never taken from a clock</p>\n","type":"text/plain"},"key":"asOnDate","value":"{{financialYear}}-10-31"}],"variable":[]}},"response":[{"id":"5bf65c22-70dc-0859-533c-3e2d40a2afea","name":"SYNTHETIC — 200 snapshot.customers.dashboard (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/{{customerId}}/dashboard?asOnDate={{financialYear}}-10-31","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","{{customerId}}","dashboard"],"query":[{"key":"asOnDate","value":"{{financialYear}}-10-31"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"customer_id\": 0,\n    \"customer_name\": \"Synthetic customer_name\",\n    \"customer_print_name\": \"Synthetic customer_print_name\",\n    \"closing_balance\": 0,\n    \"pending_balance\": 0,\n    \"due_balance\": 0,\n    \"credit_limit\": 0,\n    \"total_sales_amount\": 0,\n    \"total_receipts_amount\": 0,\n    \"total_sale_returns_amount\": 0\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.customers.dashboard\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"6272b4ce0ef4aa0a\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Folio1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran3\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"511e78d3-98b2-426c-9d2c-61f1bb9d2ced"},{"name":"One customer's pending bills","id":"d5a298fa-6fa3-49d9-bc2d-c7a9eb2145ff","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/{{customerId}}/pending-bills?asOnDate={{financialYear}}-10-31&isDue=true","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/customers/{customerId}/pending-bills</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.customers.bills.pending</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/customer-pending-bills</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>path: customerId; asOnDate</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { user_id, account_name, salesman_code, transaction_date, transaction_date_raw, transaction_type, reference_number, invoice_number, total_reference_amount, total_pending_amount, is_due, due_date, due_date_raw, days_until_due, days_overdue }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, customerId, isDue, calculationDate, source, snapshot, filters { asOnDate, isDue }, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (a salesman or broker has more than one address row); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>asOnDate is required (the twin uses the PC's UTC date): is_due, days_until_due and days_overdue are counted from it. The customer's eligible traces (Tran3.MasterCode1) whose rounded pending amount is not 0 (isDue=true: due on or before asOnDate); user_id is the resolved customer; salesman_code is the telephone of the voucher's salesman (Tran1.CM4) or else the bill's broker. An unknown customer answers an empty list, as the twin. Paged (the twin is unpaged); ordered by days_until_due (none first), bill date, reference number (binary), then reference, voucher and line.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>customerId</code></td>\n<td>path</td>\n<td>integer</td>\n<td>yes</td>\n<td>whole number from 1 to 2147483647: the customer's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>asOnDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>yes</td>\n<td>a real calendar date written YYYY-MM-DD, inside the financial year (1 April to 31 March): the day the answer is calculated for. Never taken from a clock</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>isDue</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): only bills already due</td>\n<td>false</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/customers/1001/pending-bills?asOnDate=2025-10-31&amp;isDue=true\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","{{customerId}}","pending-bills"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD, inside the financial year (1 April to 31 March): the day the answer is calculated for. Never taken from a clock</p>\n","type":"text/plain"},"key":"asOnDate","value":"{{financialYear}}-10-31"},{"description":{"content":"<p>true or false (exactly; any other text is refused): only bills already due</p>\n","type":"text/plain"},"key":"isDue","value":"true"}],"variable":[]}},"response":[{"id":"b01096c3-c558-2f4b-4ad9-a493a17c2217","name":"SYNTHETIC — 200 snapshot.customers.bills.pending (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/{{customerId}}/pending-bills?asOnDate={{financialYear}}-10-31&isDue=true","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","{{customerId}}","pending-bills"],"query":[{"key":"asOnDate","value":"{{financialYear}}-10-31"},{"key":"isDue","value":"true"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.customers.bills.pending\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"539b6a635422465b\",\n      \"tables\": [\n        {\n          \"table\": \"Tran3\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"d5a298fa-6fa3-49d9-bc2d-c7a9eb2145ff"},{"name":"One customer's bill-wise statement","id":"0713d4d0-dce7-4aab-9758-ce51845a129a","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/{{customerId}}/bill-wise-statement?asOnDate={{financialYear}}-10-31","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/customers/{customerId}/bill-wise-statement</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.customers.bills.statement</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/customer-bill-wise-statement</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>path: customerId; asOnDate</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { reference_number, transaction_type, transaction_date, transaction_date_raw, total_reference_amount, receivable_amount, payable_amount, due_date, due_date_raw, due_days, ref_code, voucher_code, voucher_type, voucher_series_code, signed_balance }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, customerId, calculationDate, source, snapshot, filters { asOnDate }, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>asOnDate is required (the twin uses the PC's UTC date): due_days = asOnDate − due date (the bill date when there is none). The customer's traces (record type 1, method 1, MasterCode2 = 0, approval status not 2) whose signed balance (Σ Value1 of the reference without rejected rows) rounds to anything but 0; negative = receivable_amount, positive = payable_amount. An unknown customer answers an empty list, as the twin. Paged (the twin is unpaged); ordered by bill date (none first), voucher type, reference number (binary), then reference, voucher and line.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>customerId</code></td>\n<td>path</td>\n<td>integer</td>\n<td>yes</td>\n<td>whole number from 1 to 2147483647: the customer's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>asOnDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>yes</td>\n<td>a real calendar date written YYYY-MM-DD, inside the financial year (1 April to 31 March): the day the answer is calculated for. Never taken from a clock</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/customers/1001/bill-wise-statement?asOnDate=2025-10-31\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","{{customerId}}","bill-wise-statement"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD, inside the financial year (1 April to 31 March): the day the answer is calculated for. Never taken from a clock</p>\n","type":"text/plain"},"key":"asOnDate","value":"{{financialYear}}-10-31"}],"variable":[]}},"response":[{"id":"58b3bf5e-c684-1c39-0515-3ed8c46edda4","name":"SYNTHETIC — 200 snapshot.customers.bills.statement (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/{{customerId}}/bill-wise-statement?asOnDate={{financialYear}}-10-31","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","{{customerId}}","bill-wise-statement"],"query":[{"key":"asOnDate","value":"{{financialYear}}-10-31"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.customers.bills.statement\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"6d88de22a379fddb\",\n      \"tables\": [\n        {\n          \"table\": \"Tran3\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"0713d4d0-dce7-4aab-9758-ce51845a129a"},{"name":"Suppliers","id":"b5aec914-4af0-4d9e-8cbf-8c52b7efa779","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/suppliers?includeContactDetails=true&pageSize=100","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/suppliers</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.suppliers.list</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/suppliers</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { supplier_id, supplier_name, supplier_alias, supplier_print_name, supplier_group_id, supplier_group_name, purchase_voucher_count, purchase_return_voucher_count, purchase_order_count, has_purchase_vouchers, has_purchase_returns, has_purchase_orders, gst_number, mobile_number }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, supplierId, searchApplied, includeContactDetails, source, snapshot, filters (never the search text), pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (a listed supplier has several address rows and includeContactDetails is true); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>A supplier is an account master (Master1 type 2) with at least one purchase (2), purchase-return (10) or purchase-order (13) header that is not cancelled and names it as Tran1.MasterCode1 (&gt; 0), or that is the Tran3.MasterCode2 (&gt; 0) of a purchase-order trace (record type 4, method 1, type 13) whose order header, if any, is not cancelled. Counts are distinct voucher codes; purchase_order_count is the larger of distinct order headers and distinct order references; has_* are 1/0. gst_number and mobile_number are null unless includeContactDetails is true; then they are the address row's values trimmed of spaces (blank = null), and a listed supplier with several address rows refuses the answer (the twin). search (JavaScript-trimmed, at most 200 characters, blank = none; never echoed or logged) finds the text in name + ' ' + alias + ' ' + print name, ASCII letters case-insensitively (SQLite LOWER/INSTR). A group code held by several masters repeats the supplier once per group name (the twin). Ordered by name as SQLite COLLATE NOCASE (none first, ASCII folded, then UTF-8 bytes), code, group name. Cancellation is the shared BusyFlagsV1 rule (Tran1.Cancelled or VchCancelled is true, the number 1 or -1, or text that — white space trimmed as .NET trims it, case-insensitive — is true, yes, y or a number equal to 1 or -1, such as 1, -1, 1.0, +1); a line or row without a header is not cancelled.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>supplierId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the supplier's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>search</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>trimmed, at most 200 characters; blank = none; never echoed in the answer or logged</td>\n<td>none</td>\n</tr>\n<tr>\n<td><code>includeContactDetails</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): add the supplier's address and contact fields</td>\n<td>false</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/suppliers?includeContactDetails=true&amp;pageSize=100\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","suppliers"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>true or false (exactly; any other text is refused): add the supplier's address and contact fields</p>\n","type":"text/plain"},"key":"includeContactDetails","value":"true"},{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"100"}],"variable":[]}},"response":[{"id":"9a6a93db-804b-de40-bd15-4a665a253290","name":"SYNTHETIC — 200 snapshot.suppliers.list (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/suppliers?includeContactDetails=true&pageSize=100","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","suppliers"],"query":[{"key":"includeContactDetails","value":"true"},{"key":"pageSize","value":"100"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.suppliers.list\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"6d88de22a379fddb\",\n      \"tables\": [\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran3\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"b5aec914-4af0-4d9e-8cbf-8c52b7efa779"},{"name":"Supplier ledger","id":"07389a50-c911-44db-b73a-bb0c8811ef4f","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/suppliers/{{supplierId}}/ledger?fromDate={{financialYear}}-04-01&toDate={{financialYear}}-09-30","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/suppliers/{supplierId}/ledger</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.suppliers.ledger</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/supplier-ledger</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>path: supplierId</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ rows: array of { ledger_row_id, voucher_code, voucher_type_id, voucher_number, voucher_date, line_number, supplier_name, supplier_id, financial_year_opening_balance, debit, credit, running_balance }, summary: { financial_year_opening_balance, period_opening_balance, period_debit, period_credit, closing_balance } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, supplierId, fromDate, toDate (as applied), source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>fromDate / toDate (each JavaScript-trimmed, blank = not sent) default to 1 April and 31 March and must lie inside the financial year, fromDate not after toDate (the twin's TryDate and range rule). The supplier's Tran2 lines of record type 1 (any master code is accepted, as the reference) from 1 April to toDate, cancelled vouchers left out (a voucher with several headers is decided per header, as the twin's join). Ordered by date, voucher code, SrNo (none first), then voucher type, amount and number. rows (from fromDate): ledger_row_id is the line's position (1, 2, …) in the year's ordered ledger of the supplier (BUSY has no row id; stable across pages and dates); debit = ROUND(−Value1, 2) when negative, credit = ROUND(Value1, 2) when positive; running_balance = ROUND(opening + every earlier line of the year + this line, 2) — correct on any page; supplier_name is the account master's (type 2) ordinal-least name, null when the code is no account master. summary (always over the whole range, never per page): financial_year_opening_balance = ROUND(Σ Folio1.D1, ascending, 2), period_opening_balance = ROUND(opening + lines before fromDate, 2), period_debit, period_credit (from fromDate), closing_balance = ROUND(opening + every line to toDate, 2); doubles summed in the twin's order. An unknown code answers no rows and a summary of its opening only (zeros when none), as the twin. Dates are BUSY dates (the twin's SuppliersV1.BusyDate of the stored text) as YYYY-MM-DD. Cancellation is the shared BusyFlagsV1 rule (Tran1.Cancelled or VchCancelled is true, the number 1 or -1, or text that — white space trimmed as .NET trims it, case-insensitive — is true, yes, y or a number equal to 1 or -1, such as 1, -1, 1.0, +1); a line or row without a header is not cancelled.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>supplierId</code></td>\n<td>path</td>\n<td>integer</td>\n<td>yes</td>\n<td>whole number from 1 to 2147483647: the supplier's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/suppliers/3001/ledger?fromDate=2025-04-01&amp;toDate=2025-09-30\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","suppliers","{{supplierId}}","ledger"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-04-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"toDate","value":"{{financialYear}}-09-30"}],"variable":[]}},"response":[{"id":"23a4cc26-fc3d-704b-cb01-c9474dbdd073","name":"SYNTHETIC — 200 snapshot.suppliers.ledger (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/suppliers/{{supplierId}}/ledger?fromDate={{financialYear}}-04-01&toDate={{financialYear}}-09-30","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","suppliers","{{supplierId}}","ledger"],"query":[{"key":"fromDate","value":"{{financialYear}}-04-01"},{"key":"toDate","value":"{{financialYear}}-09-30"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"rows\": [],\n    \"summary\": {\n      \"financial_year_opening_balance\": 0,\n      \"period_opening_balance\": \"Synthetic period_opening_balance\",\n      \"period_debit\": \"Synthetic period_debit\",\n      \"period_credit\": \"Synthetic period_credit\",\n      \"closing_balance\": 0\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.suppliers.ledger\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"b4046551b72fbfd4\",\n      \"tables\": [\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Folio1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"07389a50-c911-44db-b73a-bb0c8811ef4f"},{"name":"Supplier pending bills","id":"d448a6b0-cc78-4711-82cc-d6f9cd7244b0","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/suppliers/pending-bills?asOfDate={{financialYear}}-10-31&status=open","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/suppliers/pending-bills</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.suppliers.bills.pending</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/supplier-pending-bills</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>asOfDate</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { supplier_id, supplier_name, bill_reference_code, reference_number, origin_voucher_code, origin_voucher_type_id, bill_date, due_date, original_amount, pending_amount, allocation_count, allocated_amount, status, days_overdue, is_unadjusted_credit, allocations: array of { voucher_code, voucher_type_id, voucher_number, allocation_date, amount, signed_amount, bill_reference_code, bill_reference_number } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, supplierId (null for every supplier), status, includeCredits, asOfDate, source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>asOfDate is required (the twin defaults to today's UTC date kept inside the year; a snapshot has no single \"today\") and must lie inside the financial year; it is never defaulted or clamped. supplierId is optional (every supplier when absent, the twin's rule; owner-approved route, 9 October 2026). status open (pending ≠ 0, default), closed (= 0) or all, case-insensitive; includeCredits (default true) false leaves out every row whose pending amount is negative. Reference rows: Tran3 record type 1 with a RefCode, dated on or before asOfDate, not cancelled. Bills are keyed by the exact (Tran3.MasterCode1, RefCode): the origin is the first method-1 row (by date, voucher code, type, SrNo, amount) that is positive on voucher types 1, 2, 16, 18 or negative on 10, 16, 17, 19; its party must be a supplier (a non-cancelled purchase, purchase-return or purchase-order header) and an account master. pending_amount = ROUND(Σ Value1, 2) of every reference row of that supplier and code; allocations are its method-2 rows. No FIFO or inferred matching: another supplier's row, a cancelled row or a row after asOfDate is never counted. On-account credits: a supplier's negative Tran2 line of record type 1 and voucher type 10, 16, 17 or 19, not cancelled, on or before asOfDate, of a voucher with no reference row of that supplier and type; one per voucher (the line with the highest SrNo, then the least amount and date): bill_reference_code null, reference_number = the voucher number (or code), status Credit, is_unadjusted_credit 1, allocations []. reference_number = Tran3.No trimmed, else the code; original_amount = ROUND(|origin|, 2); allocated_amount = ROUND(Σ|allocation|, 2); status Payable (&gt; 0), Credit (&lt; 0), Closed (= 0); days_overdue = asOfDate − due date, at least 0 (null without a due date). allocations is always an array: each allocation's voucher_number is the header's VchNo, else Tran3.No, else the code; ordered by the key allocation_date + \":\" + voucher_code (ordinal), then type, SrNo, amount. An account master code held by several rows repeats the bill per name (the twin). Ordered by bill date, supplier, reference code (on-account credits first), origin voucher, type, name. Dates are BUSY dates (the twin's SuppliersV1.BusyDate of the stored text) as YYYY-MM-DD. Cancellation is the shared BusyFlagsV1 rule (Tran1.Cancelled or VchCancelled is true, the number 1 or -1, or text that — white space trimmed as .NET trims it, case-insensitive — is true, yes, y or a number equal to 1 or -1, such as 1, -1, 1.0, +1); a line or row without a header is not cancelled.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>supplierId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the supplier's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>status</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>open, closed or all (any case)</td>\n<td>open</td>\n</tr>\n<tr>\n<td><code>includeCredits</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): add on-account supplier credits</td>\n<td>true</td>\n</tr>\n<tr>\n<td><code>asOfDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>yes</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year: the day the answer is calculated for. Never taken from a clock</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/suppliers/pending-bills?asOfDate=2025-10-31&amp;status=open\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","suppliers","pending-bills"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year: the day the answer is calculated for. Never taken from a clock</p>\n","type":"text/plain"},"key":"asOfDate","value":"{{financialYear}}-10-31"},{"description":{"content":"<p>open, closed or all (any case)</p>\n","type":"text/plain"},"key":"status","value":"open"}],"variable":[]}},"response":[{"id":"51f4c1ff-0195-37ee-3a44-de1c20932a8a","name":"SYNTHETIC — 200 snapshot.suppliers.bills.pending (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/suppliers/pending-bills?asOfDate={{financialYear}}-10-31&status=open","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","suppliers","pending-bills"],"query":[{"key":"asOfDate","value":"{{financialYear}}-10-31"},{"key":"status","value":"open"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.suppliers.bills.pending\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"93b0f4f7630d751d\",\n      \"tables\": [\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran3\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"d448a6b0-cc78-4711-82cc-d6f9cd7244b0"}],"id":"95aa8184-d080-4ce9-8d6b-431f66f950f0","description":"<p>Snapshot reads of the reports in the live family <em>Customer and supplier accounting</em> (7); each request names its live equivalent.</p>\n<ul>\n<li><strong>Customers with pending bills</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/customers/pending-bills</code></li>\n<li><strong>Customer dashboard</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/customers/{customerId}/dashboard</code></li>\n<li><strong>One customer's pending bills</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/customers/{customerId}/pending-bills</code></li>\n<li><strong>One customer's bill-wise statement</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/customers/{customerId}/bill-wise-statement</code></li>\n<li><strong>Suppliers</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/suppliers</code></li>\n<li><strong>Supplier ledger</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/suppliers/{supplierId}/ledger</code></li>\n<li><strong>Supplier pending bills</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/suppliers/pending-bills</code></li>\n</ul>\n","_postman_id":"95aa8184-d080-4ce9-8d6b-431f66f950f0","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Ledgers, analytics and summaries","item":[{"name":"Customer ledger","id":"68426b6d-12d7-4a84-a2e3-93a10e020fb8","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/{{customerId}}/ledger?fromDate={{financialYear}}-04-01&toDate={{financialYear}}-09-30&pageSize=200","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/customers/{customerId}/ledger</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.customers.ledger</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/customer-ledger</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>path: customerId</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { user_id, opening_balance, user_id2, transaction_date_iso, formatted_date, voucher_type, voucher_no, account_name, debit, credit, voucher_code, on_account, financial_year }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, financialYears, customerId, fromDate, toDate, source, snapshot (setId over every year, tables[] with financialYear, years[] with each year's own setId and read times), filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 400 INVALID_PARAMETER (field additionalFinancialYears: more years than the technical maximum); 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear } (any requested year without published data); 404 SNAPSHOT_TABLE_MISSING { table, financialYear }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Member names follow this surface: fromDate/toDate/additionalFinancialYears are the twin's startDate/endDate/additionalFinancialYear. The years are the path year, then each additional year in the order sent, each once (a repeated year is ignored, as the twin); at most the technical maximum (5 by default) in one request — never a plan count. Every year must have its own published snapshot of the same company; each year is read from its own set (one query job per year) and reported in metadata.snapshot.years. fromDate/toDate are real dates, not bounded to a year, and apply to every year. Per year, as the twin: the customer's Tran2 record-type 1 lines ordered by VchCode, DATE(Date), SrNo; opening_balance = RoundTwo(Σ Folio1.D1 + the lines dated before fromDate), the same on every row of that year; the counter-party and on_account rules of the twin. Rows are the years concatenated in request order; paged over that whole list (the twin is unpaged) with totalRows exact. An unknown customer answers an empty list, as the twin.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>customerId</code></td>\n<td>path</td>\n<td>integer</td>\n<td>yes</td>\n<td>whole number from 1 to 2147483647: the customer's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>additionalFinancialYears</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>comma-separated four-digit starting years, e.g. 2024,2025 (blank entries ignored; a repeat is ignored). Each year is read from its own published data; at most 5 years in one request, counting the path year</td>\n<td>none (the path year only)</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/customers/1001/ledger?fromDate=2025-04-01&amp;toDate=2025-09-30&amp;pageSize=200\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","{{customerId}}","ledger"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-04-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"toDate","value":"{{financialYear}}-09-30"},{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"200"}],"variable":[]}},"response":[{"id":"d5209028-764c-26cd-244d-73efdd035147","name":"SYNTHETIC — 200 snapshot.customers.ledger (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/{{customerId}}/ledger?fromDate={{financialYear}}-04-01&toDate={{financialYear}}-09-30&pageSize=200","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","{{customerId}}","ledger"],"query":[{"key":"fromDate","value":"{{financialYear}}-04-01"},{"key":"toDate","value":"{{financialYear}}-09-30"},{"key":"pageSize","value":"200"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.customers.ledger\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"63b775ea1910cb92\",\n      \"tables\": [\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran3\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"68426b6d-12d7-4a84-a2e3-93a10e020fb8"},{"name":"Account monthly summary","id":"55b82fe0-df4c-457d-a1c1-ddbca5929a59","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/accounts/monthly-summary?pageSize=100","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/accounts/monthly-summary</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.accounts.monthly-summary</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/account-monthly-summary</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ rows: array of { account_id, account_name, opening_balance, opening_balance_type, opening_balance_display, april_debit, april_credit … march_debit, march_credit, closing_balance, closing_balance_type, closing_balance_display, opening_signed, closing_signed }, totals: { opening_balance_total, opening_balance_total_type, opening_balance_total_display, april_debit_total … march_credit_total, closing_balance_total, closing_balance_total_type, closing_balance_total_display, opening_signed_total, closing_signed_total } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, fromDate, toDate (the whole year), source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (a Master1 code is repeated); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>As the twin: every account of master type 2 with I10 0 (a missing value counting as 0); opening = ROUND2(Σ ROUND2(Folio1.D1) of type-2 rows); April–March debit and credit columns of the record-type 1 lines dated in the year (BUSY date text read as the twin reads it), each month rounded; closing = ROUND2(opening + Σ ROUND2(month signed)); accounts whose every value is 0 are left out; ordered by trimmed name (binary), then code. data.totals are over every account of the year, computed before the page is cut — never over the returned page. Exact decimal sums rounded half away from zero.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/accounts/monthly-summary?pageSize=100\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","accounts","monthly-summary"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"100"}],"variable":[]}},"response":[{"id":"715b358b-2cb9-718e-40a2-b73ab6f0d7ad","name":"SYNTHETIC — 200 snapshot.accounts.monthly-summary (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/accounts/monthly-summary?pageSize=100","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","accounts","monthly-summary"],"query":[{"key":"pageSize","value":"100"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"rows\": [],\n    \"totals\": {\n      \"opening_balance_total\": 0,\n      \"opening_balance_total_type\": \"Synthetic opening_balance_total_type\",\n      \"opening_balance_total_display\": \"Synthetic opening_balance_total_display\",\n      \"closing_balance_total\": 0,\n      \"closing_balance_total_type\": \"Synthetic closing_balance_total_type\",\n      \"closing_balance_total_display\": \"Synthetic closing_balance_total_display\",\n      \"opening_signed_total\": 0,\n      \"closing_signed_total\": 0,\n      \"april_debit_total\": 0,\n      \"april_credit_total\": 0,\n      \"may_debit_total\": 0,\n      \"may_credit_total\": 0,\n      \"june_debit_total\": 0,\n      \"june_credit_total\": 0,\n      \"july_debit_total\": 0,\n      \"july_credit_total\": 0,\n      \"august_debit_total\": 0,\n      \"august_credit_total\": 0,\n      \"september_debit_total\": 0,\n      \"september_credit_total\": 0,\n      \"october_debit_total\": 0,\n      \"october_credit_total\": 0,\n      \"november_debit_total\": 0,\n      \"november_credit_total\": 0,\n      \"december_debit_total\": 0,\n      \"december_credit_total\": 0,\n      \"january_debit_total\": 0,\n      \"january_credit_total\": 0,\n      \"february_debit_total\": 0,\n      \"february_credit_total\": 0,\n      \"march_debit_total\": 0,\n      \"march_credit_total\": 0\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.accounts.monthly-summary\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"ab070938cac63727\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Folio1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"55b82fe0-df4c-457d-a1c1-ddbca5929a59"},{"name":"Account consolidated summary","id":"de57252e-5866-411c-b779-337875b7ba4a","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/accounts/consolidated-summary?fromDate={{financialYear}}-04-01&toDate={{financialYear}}-09-30","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/accounts/consolidated-summary</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.accounts.consolidated-summary</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/account-consolidated-summary</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ rows: array of { account_id, account_name, parent_group_id, parent_group_name, opening_balance_dr, opening_balance_cr, debit_amount, credit_amount, closing_balance_dr, closing_balance_cr, note_text, opening_signed, closing_signed }, totals: { opening_balance_dr_total, opening_balance_cr_total, debit_total, credit_total, closing_balance_dr_total, closing_balance_cr_total } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, fromDate, toDate (as applied), source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (a Master1 code is repeated); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>The range rule of the twin: neither date = the whole year, one date alone = that one day, both = the range (inside the year, fromDate not after toDate). As the twin: accounts of master type 2 with I10 0 that have a Folio1 row of type 2 (the reference's INNER JOIN, kept and documented); opening = ROUND2(Folio1 + ROUND2(lines from 1 April before fromDate)); debit and credit of the range; closing = ROUND2(Folio1 + that + ROUND2(range signed)); all-zero accounts left out; parent_group_name from Help1 (name rows, NULL first, then binary order) else the group master's name. data.totals are over every listed account, computed before the page is cut. Exact decimal sums rounded half away from zero.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/accounts/consolidated-summary?fromDate=2025-04-01&amp;toDate=2025-09-30\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","accounts","consolidated-summary"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-04-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"toDate","value":"{{financialYear}}-09-30"}],"variable":[]}},"response":[{"id":"61036471-118a-b931-d0b2-99683d9f24b4","name":"SYNTHETIC — 200 snapshot.accounts.consolidated-summary (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/accounts/consolidated-summary?fromDate={{financialYear}}-04-01&toDate={{financialYear}}-09-30","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","accounts","consolidated-summary"],"query":[{"key":"fromDate","value":"{{financialYear}}-04-01"},{"key":"toDate","value":"{{financialYear}}-09-30"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"rows\": [],\n    \"totals\": {\n      \"opening_balance_dr_total\": 0,\n      \"opening_balance_cr_total\": 0,\n      \"debit_total\": 0,\n      \"credit_total\": 0,\n      \"closing_balance_dr_total\": 0,\n      \"closing_balance_cr_total\": 0\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.accounts.consolidated-summary\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"116963f9e7dae84d\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Folio1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Help1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"de57252e-5866-411c-b779-337875b7ba4a"},{"name":"Item ledger","id":"8d63b99c-ad79-4e42-9441-2019da3b4685","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/items/{{productId}}/ledger?fromDate={{financialYear}}-04-01&toDate={{financialYear}}-06-30","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/items/{productId}/ledger</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.items.ledger</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/single-item-ledger</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>path: productId</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ product: { product_id, product_name, product_alias, product_group_id, product_group_name, unit_id, unit_name }, summary: { opening_quantity, opening_amount, quantity_in, amount_in, quantity_out, amount_out, closing_quantity, closing_amount, tran4_control_quantity, tran4_control_amount }, ledger: array of { date, voucher_type, voucher_type_id, voucher_number, voucher_code, sr_no, party_id, party_name, material_center_id, material_center_name, particulars, quantity_in, amount_in, quantity_out, amount_out, balance_quantity, balance_amount } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, productId, fromDate, toDate (as applied), source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 NOT_FOUND (field productId: not a product); 422 SNAPSHOT_SCHEMA_UNSUPPORTED (a line without a voucher code or type); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>fromDate / toDate inside the year, each missing side the year's own bound (the twin's rule). As the twin: the item's stock lines (Tran2 record type 2) of every voucher type but stock transfer (5), dated by the BUSY date text; opening = Σ Folio1.D1 / D3 + the lines before fromDate; lines of the range ordered by date, voucher type, number, code, line, then their own values; balance_quantity / balance_amount run from the opening over the WHOLE range, so they are correct on every page (the page is cut after the running values are computed); the summary covers the whole range; tran4_control_* = Σ Tran4.D1 / D3 (a control total). Cancelled vouchers are not left out (the reference has no rule here). Paged ledger lines (data.ledger), as the twin.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>productId</code></td>\n<td>path</td>\n<td>integer</td>\n<td>yes</td>\n<td>whole number from 1 to 2147483647: the product's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/items/2001/ledger?fromDate=2025-04-01&amp;toDate=2025-06-30\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","items","{{productId}}","ledger"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-04-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"toDate","value":"{{financialYear}}-06-30"}],"variable":[]}},"response":[{"id":"5b643a39-b77d-f876-a2fd-2a5cfb4b66a9","name":"SYNTHETIC — 200 snapshot.items.ledger (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/items/{{productId}}/ledger?fromDate={{financialYear}}-04-01&toDate={{financialYear}}-06-30","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","items","{{productId}}","ledger"],"query":[{"key":"fromDate","value":"{{financialYear}}-04-01"},{"key":"toDate","value":"{{financialYear}}-06-30"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"product\": {\n      \"product_id\": 0,\n      \"product_name\": \"Synthetic product_name\",\n      \"product_alias\": \"Synthetic product_alias\",\n      \"product_group_id\": 0,\n      \"product_group_name\": \"Synthetic product_group_name\",\n      \"unit_id\": \"Synthetic unit_id\",\n      \"unit_name\": \"Synthetic unit_name\"\n    },\n    \"summary\": {\n      \"opening_quantity\": 0,\n      \"opening_amount\": 0,\n      \"quantity_in\": 0,\n      \"amount_in\": 0,\n      \"quantity_out\": 0,\n      \"amount_out\": 0,\n      \"closing_quantity\": 0,\n      \"closing_amount\": 0,\n      \"tran4_control_quantity\": 0,\n      \"tran4_control_amount\": 0\n    },\n    \"ledger\": []\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.items.ledger\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"30c500f6130a62f2\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Folio1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran4\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"8d63b99c-ad79-4e42-9441-2019da3b4685"},{"name":"Sales analysis — one item","id":"06fe50c6-d3d1-4ff6-bac3-c52c688cd2f3","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sales-analysis/items/{{productId}}?fromDate={{financialYear}}-04-01&toDate={{financialYear}}-09-30","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/sales-analysis/items/{productId}</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.sales-analysis.item</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/sales-analysis-single-item</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>path: productId</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ item: { product_id, product_name, product_alias, product_group_id, product_group_name, unit }, rows: array of { customer_id, customer_name, sale_quantity, return_quantity, net_sale_quantity, unit, sale_amount, return_amount, net_sale_amount, average_price, sale_voucher_count, sale_return_voucher_count }, summary: { sale_quantity_total, return_quantity_total, net_sale_quantity_total, sale_amount_total, return_amount_total, net_sale_amount_total, average_price_total } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, productId, fromDate, toDate (as applied), source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 NOT_FOUND (field productId: not a product); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>fromDate / toDate inside the year, each missing side the year's own bound (the twin's rule); lines dated by the BUSY date text. One classification for every analysis (the twin's owner-ordered correction): Tran2 record types 2 and 7 of a sale voucher (9) without the IsReturnQty flag are sales; a sales-return voucher (3), or a sale-voucher line with the flag (BUSY Yes/No: true, 1, -1, yes, y), is a return; quantities and amounts are absolute values. Cancelled vouchers are not left out (the reference has no rule here). <strong>Only sale types (Tran2.CM4, Master1 type 13) whose B18 and B15 flags are not set count</strong> (blank or NULL is not set; a line without a sale type does not count). One row per customer (Tran2.CM1), by name (binary) then code: quantities and amounts summed and rounded to 2, net = sale − return, average price = ROUND(net amount ÷ net quantity, 2) (0 when the net quantity is 0), voucher counts = distinct voucher codes with a non-zero amount. The summary covers every row of the range, never one page. Paged by customer (data.rows).</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>productId</code></td>\n<td>path</td>\n<td>integer</td>\n<td>yes</td>\n<td>whole number from 1 to 2147483647: the product's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/sales-analysis/items/2001?fromDate=2025-04-01&amp;toDate=2025-09-30\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","sales-analysis","items","{{productId}}"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-04-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"toDate","value":"{{financialYear}}-09-30"}],"variable":[]}},"response":[{"id":"4b2369be-4cfd-6f44-1261-f49249dc37de","name":"SYNTHETIC — 200 snapshot.sales-analysis.item (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sales-analysis/items/{{productId}}?fromDate={{financialYear}}-04-01&toDate={{financialYear}}-09-30","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","sales-analysis","items","{{productId}}"],"query":[{"key":"fromDate","value":"{{financialYear}}-04-01"},{"key":"toDate","value":"{{financialYear}}-09-30"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"item\": {\n      \"product_id\": 0,\n      \"product_name\": \"Synthetic product_name\",\n      \"product_alias\": \"Synthetic product_alias\",\n      \"product_group_id\": 0,\n      \"product_group_name\": \"Synthetic product_group_name\",\n      \"unit\": \"Synthetic unit\"\n    },\n    \"rows\": [],\n    \"summary\": {\n      \"sale_quantity_total\": 0,\n      \"return_quantity_total\": 0,\n      \"net_sale_quantity_total\": 0,\n      \"sale_amount_total\": 0,\n      \"return_amount_total\": 0,\n      \"net_sale_amount_total\": 0,\n      \"average_price_total\": 0\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.sales-analysis.item\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"9776a1e13d2f59af\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"06fe50c6-d3d1-4ff6-bac3-c52c688cd2f3"},{"name":"Sales analysis — one customer","id":"c8395535-b321-4cf2-b39a-9e6901047ae7","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sales-analysis/customers/{{customerId}}","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/sales-analysis/customers/{customerId}</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.sales-analysis.customer</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/sales-analysis-single-customer</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>path: customerId</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ customer: { customer_id, customer_name, customer_alias }, rows: array of { product_id, product_name, product_alias, product_group_id, product_group_name, main_unit, alternative_unit, sale_quantity_main, sale_quantity_alternative, return_quantity_main, return_quantity_alternative, net_sale_quantity_main, net_sale_quantity_alternative, sale_amount, return_amount, net_sale_amount, average_price_main, average_price_alternative, sale_voucher_count, sale_return_voucher_count }, summary: { sale_quantity_main_total, sale_quantity_alternative_total, return_quantity_main_total, return_quantity_alternative_total, net_sale_quantity_main_total, net_sale_quantity_alternative_total, sale_amount_total, return_amount_total, net_sale_amount_total, average_price_main_total, average_price_alternative_total } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, customerId, fromDate, toDate (as applied), source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 NOT_FOUND (field customerId: not a customer); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>fromDate / toDate inside the year, each missing side the year's own bound (the twin's rule); lines dated by the BUSY date text. One classification for every analysis (the twin's owner-ordered correction): Tran2 record types 2 and 7 of a sale voucher (9) without the IsReturnQty flag are sales; a sales-return voucher (3), or a sale-voucher line with the flag (BUSY Yes/No: true, 1, -1, yes, y), is a return; quantities and amounts are absolute values. Cancelled vouchers are not left out (the reference has no rule here). <strong>No sale-type filter</strong> (the twin and the reference; only the item analysis filters sale types). One row per product (Tran2.MasterCode1), by name (binary) then code: main (Value1) and alternative (Value2) quantities, amounts (Value3), net values and average prices per unit (0 when the quantity is 0), voucher counts = distinct voucher codes with a quantity or an amount. The summary covers every row of the range. Tran2 has no CM1 index: the read walks the year's sale and return lines by voucher type. Paged by product (data.rows).</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>customerId</code></td>\n<td>path</td>\n<td>integer</td>\n<td>yes</td>\n<td>whole number from 1 to 2147483647: the customer's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/sales-analysis/customers/1001\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","sales-analysis","customers","{{customerId}}"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"0fbce319-d59f-2d0c-e181-f7268a382898","name":"SYNTHETIC — 200 snapshot.sales-analysis.customer (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sales-analysis/customers/{{customerId}}"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"customer\": {\n      \"customer_id\": 0,\n      \"customer_name\": \"Synthetic customer_name\",\n      \"customer_alias\": \"Synthetic customer_alias\"\n    },\n    \"rows\": [],\n    \"summary\": {\n      \"sale_quantity_main_total\": 0,\n      \"sale_quantity_alternative_total\": 0,\n      \"return_quantity_main_total\": 0,\n      \"return_quantity_alternative_total\": 0,\n      \"net_sale_quantity_main_total\": 0,\n      \"net_sale_quantity_alternative_total\": 0,\n      \"sale_amount_total\": 0,\n      \"return_amount_total\": 0,\n      \"net_sale_amount_total\": 0,\n      \"average_price_main_total\": 0,\n      \"average_price_alternative_total\": 0\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.sales-analysis.customer\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"9776a1e13d2f59af\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"c8395535-b321-4cf2-b39a-9e6901047ae7"},{"name":"Customer product analytics","id":"2ca18c08-8426-4829-8f08-5c04b4d796a3","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/{{customerId}}/product-analytics","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/customers/{customerId}/product-analytics</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.customers.product-analytics</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/customer-product-analytics</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>path: customerId</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ customer: { customer_id, customer_name, customer_alias }, summary: { total_product_count, active_product_count, dropped_product_count, sale_quantity_main_total, sale_quantity_alternative_total, return_quantity_main_total, return_quantity_alternative_total, net_sale_quantity_main_total, net_sale_quantity_alternative_total, sale_amount_total, return_amount_total, net_sale_amount_total, taxable_amount_total, gst_amount_total, cgst_amount_total, sgst_amount_total, igst_amount_total, sale_invoice_count_total, sale_return_invoice_count_total }, active_products: array of product, dropped_products: array of product } — product = { product_id, product_name, product_alias, product_group_id, product_group_name, main_unit, alternative_unit, product_status, sale_quantity_main, sale_quantity_alternative, return_quantity_main, return_quantity_alternative, net_sale_quantity_main, net_sale_quantity_alternative, sale_amount, return_amount, net_sale_amount, taxable_amount, gst_amount, cgst_amount, sgst_amount, igst_amount, sale_invoice_count, sale_return_invoice_count, last_purchase_rate, average_rate, min_rate, max_rate, weighted_average_rate, first_purchase_date, last_purchase_date, days_since_last_purchase, purchase_frequency_count, average_purchase_interval_days, daily_trend, weekly_trend, monthly_trend } and a trend point = { period, sale_quantity_main, net_sale_quantity_main, net_sale_amount, sale_invoice_count }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, financialYears, customerId, fromDate, toDate (as applied), source, snapshot (setId over every year, tables[] with financialYear, years[] with each year's own setId and read times), filters, pagination (totalRows = total_product_count), rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 400 INVALID_PARAMETER (field fromDate: the period touches a year that is not requested; field additionalFinancialYears: more years than the technical maximum); 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear } (any requested year without published data); 404 NOT_FOUND (field customerId: no year read for the period holds the customer); 404 SNAPSHOT_TABLE_MISSING { table, financialYear }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE (the page; lower pageSize — the trends make a product row large)</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>The years are the path year (primary), then each additionalFinancialYears year in the order sent, each once, at most the technical maximum; every year must have its own published snapshot of the company (metadata.snapshot.years). One query job reads them: it opens each year's own set in turn (never attached together) and streams the customer's lines in the twin's order three times, holding per-product state (memory grows with the number of distinct invoices, not of lines) and only the page leaves the process — the job-result bound applies to the page, not to the history; the cross-year classification and the twin's order of every running total hold exactly. A history too large for the job's heap or time budget is refused (503 / 504), never answered in part. Period: fromDate / toDate default to the primary year; each may lie in any requested year, but every financial year the period touches must be requested (else 400, field fromDate). Each year contributes its customer lines from its own 1 April to the earlier of its 31 March and toDate (lines before fromDate are history; a year starting after toDate contributes nothing); the customer is the first such year whose Master1 holds it as a customer (else 404). One classification for every analysis (the twin's owner-ordered correction): Tran2 record types 2 and 7 of a sale voucher (9) without the IsReturnQty flag are sales; a sales-return voucher (3), or a sale-voucher line with the flag (BUSY Yes/No: true, 1, -1, yes, y), is a return; quantities and amounts are absolute values. Cancelled vouchers are not left out (the reference has no rule here). Active product: a line inside the period; dropped product: none inside but a sale before fromDate; never both. Per product: main / alternative quantities, amounts (taxable), GST / CGST / SGST / IGST (GST rows of record type 0 or NULL of one item line are one; location type 0 = CGST + SGST, else IGST), invoice counts by financial year + voucher code; purchase history over every sale line up to toDate (last / average / min / max line rate, weighted average, first and last purchase date, days since the last purchase to toDate, purchase frequency, average interval); daily (YYYY-MM-DD), ISO-week (YYYY-Www, the week-numbering year) and monthly (YYYY-MM) trends over the period, totals rounded as they run. Active by net sale amount (highest first), then name (binary), then code; dropped by the last purchase date (latest first), then name, then code. Paged over the one sequence active then dropped (active_products / dropped_products hold the page's part of each); the summary covers every active product and never depends on the page.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>customerId</code></td>\n<td>path</td>\n<td>integer</td>\n<td>yes</td>\n<td>whole number from 1 to 2147483647: the customer's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; must lie inside a requested financial year</td>\n<td>the path year's 1 April</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; must lie inside a requested financial year</td>\n<td>the path year's 31 March</td>\n</tr>\n<tr>\n<td><code>additionalFinancialYears</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>comma-separated four-digit starting years, e.g. 2024,2025 (blank entries ignored; a repeat is ignored). Each year is read from its own published data; at most 5 years in one request, counting the path year</td>\n<td>none (the path year only)</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/customers/1001/product-analytics?additionalFinancialYears=2024\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","{{customerId}}","product-analytics"],"host":["{{cloudBaseUrl}}"],"query":[{"disabled":true,"description":{"content":"<p>comma-separated four-digit starting years, e.g. 2024,2025 (blank entries ignored; a repeat is ignored). Each year is read from its own published data; at most 5 years in one request, counting the path year</p>\n","type":"text/plain"},"key":"additionalFinancialYears","value":"2024"}],"variable":[]}},"response":[{"id":"d5bc5b56-9448-71a4-337c-733f15535134","name":"SYNTHETIC — 200 snapshot.customers.product-analytics (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/{{customerId}}/product-analytics"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"customer\": {\n      \"customer_id\": 0,\n      \"customer_name\": \"Synthetic customer_name\",\n      \"customer_alias\": \"Synthetic customer_alias\"\n    },\n    \"summary\": {\n      \"total_product_count\": 0,\n      \"active_product_count\": 0,\n      \"dropped_product_count\": 0,\n      \"sale_quantity_main_total\": 0,\n      \"sale_quantity_alternative_total\": 0,\n      \"return_quantity_main_total\": 0,\n      \"return_quantity_alternative_total\": 0,\n      \"net_sale_quantity_main_total\": 0,\n      \"net_sale_quantity_alternative_total\": 0,\n      \"sale_amount_total\": 0,\n      \"return_amount_total\": 0,\n      \"net_sale_amount_total\": 0,\n      \"taxable_amount_total\": 0,\n      \"gst_amount_total\": \"Synthetic gst_amount_total\",\n      \"cgst_amount_total\": \"Synthetic cgst_amount_total\",\n      \"sgst_amount_total\": \"Synthetic sgst_amount_total\",\n      \"igst_amount_total\": \"Synthetic igst_amount_total\",\n      \"sale_invoice_count_total\": 0,\n      \"sale_return_invoice_count_total\": 0\n    },\n    \"active_products\": [],\n    \"dropped_products\": []\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.customers.product-analytics\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"9776a1e13d2f59af\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"2ca18c08-8426-4829-8f08-5c04b4d796a3"},{"name":"Day-end summary","id":"b9af090c-0517-4faa-a61c-b8df8b8cc0e9","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/day-end/summary?date={{financialYear}}-05-10","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/day-end/summary</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.day-end.summary</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/day-end-report-summary</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>date, or both fromDate and toDate — never both forms</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>not paged</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of the ten fixed rows { type, total_amount, cash_signed, party_signed, others_signed, total_amount_display, cash, party, others }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, reportType (\"summary\"), fromDate, toDate (as applied: the twin's startDate / endDate), cashMasterCode, source, snapshot, filters, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (a repeated Master1 code); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Dates: <code>date</code> (one day) or both <code>fromDate</code> and <code>toDate</code> (inclusive) — the twin's <code>date</code> / <code>startDate</code> + <code>endDate</code>, named as this surface names a range; each a real YYYY-MM-DD inside the financial year, JavaScript-trimmed (blank = not sent); both forms together, one side alone, a reversed range or no date are refused (the twin's rules and messages, with these member names). cashMasterCode (1–2147483647, default 1) names the cash account. Always ten rows, not paged: Opening Balance, Sales (9), Purchase (2), Sales Return (Cr. Note) (3), Purchase Return (Dr. Note) (10), Receipt (14), Payment (19), Journal (16), Contra (15), Closing Balance. Per type: the lines of transaction type 0 (a missing one does not match, as the twin's raw comparison) whose account is a Master1 type 2, split into cash (cashMasterCode) and party (every other account); others = −(cash + party); total_amount = the larger of |cash| and |party|. Opening cash = every Folio1 row of the cash code (any master type) plus every earlier record-type-1 line of it (no lower bound); closing cash = opening + the range's record-type 1 / 5, transaction-type-0 lines of the cash code (any voucher type). total_amount is null on the opening and closing rows. Lines are Tran2 account lines (record type 1 or 5) dated by BUSY date in the range; amounts are exact decimals rounded half away from zero to 2 places; signed values are negative for a debit; displays are <code>… Dr</code> (negative), <code>… Cr</code> (positive), <code>0.00</code> for zero (empty for zero on the opening and closing rows). These reads leave no cancelled voucher out (the reference reads Tran2 only), as the twin. A repeated Master1 code refuses the answer (422), as the twin.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>date</code></td>\n<td>query</td>\n<td>date</td>\n<td>see Required</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year: one day</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>see Required</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year; send with toDate</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>see Required</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year; send with fromDate</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>cashMasterCode</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the account treated as cash</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/day-end/summary?date=2025-05-10\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","day-end","summary"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year: one day</p>\n","type":"text/plain"},"key":"date","value":"{{financialYear}}-05-10"}],"variable":[]}},"response":[{"id":"704334cc-bce2-ec6a-34cd-d83787d43c4f","name":"SYNTHETIC — 200 snapshot.day-end.summary (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/day-end/summary?date={{financialYear}}-05-10","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","day-end","summary"],"query":[{"key":"date","value":"{{financialYear}}-05-10"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [\n    {\n      \"type\": \"Opening Balance\",\n      \"total_amount\": null,\n      \"cash_signed\": 0,\n      \"party_signed\": 0,\n      \"others_signed\": 0,\n      \"total_amount_display\": \"\",\n      \"cash\": \"0.00\",\n      \"party\": \"0.00\",\n      \"others\": \"0.00\"\n    },\n    {\n      \"type\": \"Sales\",\n      \"total_amount\": 0,\n      \"cash_signed\": 0,\n      \"party_signed\": 0,\n      \"others_signed\": 0,\n      \"total_amount_display\": \"0.00\",\n      \"cash\": \"0.00\",\n      \"party\": \"0.00\",\n      \"others\": \"0.00\"\n    },\n    {\n      \"type\": \"Purchase\",\n      \"total_amount\": 0,\n      \"cash_signed\": 0,\n      \"party_signed\": 0,\n      \"others_signed\": 0,\n      \"total_amount_display\": \"0.00\",\n      \"cash\": \"0.00\",\n      \"party\": \"0.00\",\n      \"others\": \"0.00\"\n    },\n    {\n      \"type\": \"Sales Return (Cr. Note)\",\n      \"total_amount\": 0,\n      \"cash_signed\": 0,\n      \"party_signed\": 0,\n      \"others_signed\": 0,\n      \"total_amount_display\": \"0.00\",\n      \"cash\": \"0.00\",\n      \"party\": \"0.00\",\n      \"others\": \"0.00\"\n    },\n    {\n      \"type\": \"Purchase Return (Dr. Note)\",\n      \"total_amount\": 0,\n      \"cash_signed\": 0,\n      \"party_signed\": 0,\n      \"others_signed\": 0,\n      \"total_amount_display\": \"0.00\",\n      \"cash\": \"0.00\",\n      \"party\": \"0.00\",\n      \"others\": \"0.00\"\n    },\n    {\n      \"type\": \"Receipt\",\n      \"total_amount\": 0,\n      \"cash_signed\": 0,\n      \"party_signed\": 0,\n      \"others_signed\": 0,\n      \"total_amount_display\": \"0.00\",\n      \"cash\": \"0.00\",\n      \"party\": \"0.00\",\n      \"others\": \"0.00\"\n    },\n    {\n      \"type\": \"Payment\",\n      \"total_amount\": 0,\n      \"cash_signed\": 0,\n      \"party_signed\": 0,\n      \"others_signed\": 0,\n      \"total_amount_display\": \"0.00\",\n      \"cash\": \"0.00\",\n      \"party\": \"0.00\",\n      \"others\": \"0.00\"\n    },\n    {\n      \"type\": \"Journal\",\n      \"total_amount\": 0,\n      \"cash_signed\": 0,\n      \"party_signed\": 0,\n      \"others_signed\": 0,\n      \"total_amount_display\": \"0.00\",\n      \"cash\": \"0.00\",\n      \"party\": \"0.00\",\n      \"others\": \"0.00\"\n    },\n    {\n      \"type\": \"Contra\",\n      \"total_amount\": 0,\n      \"cash_signed\": 0,\n      \"party_signed\": 0,\n      \"others_signed\": 0,\n      \"total_amount_display\": \"0.00\",\n      \"cash\": \"0.00\",\n      \"party\": \"0.00\",\n      \"others\": \"0.00\"\n    },\n    {\n      \"type\": \"Closing Balance\",\n      \"total_amount\": null,\n      \"cash_signed\": 0,\n      \"party_signed\": 0,\n      \"others_signed\": 0,\n      \"total_amount_display\": \"\",\n      \"cash\": \"0.00\",\n      \"party\": \"0.00\",\n      \"others\": \"0.00\"\n    }\n  ],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.day-end.summary\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"ab070938cac63727\",\n      \"tables\": [\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Folio1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"rowCount\": 10,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"b9af090c-0517-4faa-a61c-b8df8b8cc0e9"},{"name":"Detailed day-end report","id":"2675108e-d1d4-4dc2-895e-95a407335337","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/day-end/detailed?fromDate={{financialYear}}-05-01&toDate={{financialYear}}-05-31&pageSize=200","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/day-end/detailed</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.day-end.detailed</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/day-end-report-detailed</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>date, or both fromDate and toDate — never both forms</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ balances: { opening: { type, date, date_raw, voucher_no, particulars, cash_signed, bank_signed, bank_od_signed, party_signed, others_signed, cash, bank, bank_od, party, others }, closing: (the same) }, rows: array of { type, date, date_raw, voucher_no, particulars, cash_signed, bank_signed, bank_od_signed, party_signed, others_signed, cash, bank, bank_od, party, others } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, reportType (\"detailed\"), fromDate, toDate (as applied), source, snapshot, filters, pagination (over data.rows), rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (a repeated Master1 code); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Dates: <code>date</code> (one day) or both <code>fromDate</code> and <code>toDate</code> (inclusive) — the twin's <code>date</code> / <code>startDate</code> + <code>endDate</code>, named as this surface names a range; each a real YYYY-MM-DD inside the financial year, JavaScript-trimmed (blank = not sent); both forms together, one side alone, a reversed range or no date are refused (the twin's rules and messages, with these member names). cashMasterCode is not a member (the twin's detailed report does not take it). Categories from the account's parent group, or also its grandparent when that group exists as a master (documented BUSY group constants): Cash (111), then Bank (112), Bank OD (128), Party (116, 117, 1303), else Others. data.balances (never paged): the opening cash, bank and bank-OD balances on fromDate (every Folio1 row of an account — master type 2, a missing type counting as 2 — plus its record-type-1 lines from 1 April to the day before; each account's movement rounded, the category sum rounded) and the closing balances through toDate; party_signed / others_signed are null there. data.rows (paged; the twin answers one unpaged list with the balances as its first and last rows): per voucher type in the fixed order (Sales 9, Purchase 2, Sales Return 3, Purchase Return 10, Receipt 14, Payment 19, Journal 16, Contra 15), every account line of an account master (type 2) of transaction type 0 or missing in the range, its amount in its category column and 0 in the others, the type named on its first line only (decided over the whole range, whatever the page); a zero placeholder row (date empty, date_raw null) for a type without lines. Lines ordered as the twin: date, voucher number (trimmed; none first), voucher code, line number, category, account, record type; exact ties keep storage order (the twin's sort is unstable there). pagination.totalRows counts the line and placeholder rows. Lines are Tran2 account lines (record type 1 or 5) dated by BUSY date in the range; amounts are exact decimals rounded half away from zero to 2 places; signed values are negative for a debit; displays are <code>… Dr</code> (negative), <code>… Cr</code> (positive), <code>0.00</code> for zero (empty for zero on the opening and closing rows). These reads leave no cancelled voucher out (the reference reads Tran2 only), as the twin. A repeated Master1 code refuses the answer (422), as the twin.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>date</code></td>\n<td>query</td>\n<td>date</td>\n<td>see Required</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year: one day</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>see Required</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year; send with toDate</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>see Required</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year; send with fromDate</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/day-end/detailed?fromDate=2025-05-01&amp;toDate=2025-05-31&amp;pageSize=200\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","day-end","detailed"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year; send with toDate</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-05-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year; send with fromDate</p>\n","type":"text/plain"},"key":"toDate","value":"{{financialYear}}-05-31"},{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"200"}],"variable":[]}},"response":[{"id":"6080306f-6757-55c0-65cf-064c7e4de15a","name":"SYNTHETIC — 200 snapshot.day-end.detailed (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/day-end/detailed?fromDate={{financialYear}}-05-01&toDate={{financialYear}}-05-31&pageSize=200","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","day-end","detailed"],"query":[{"key":"fromDate","value":"{{financialYear}}-05-01"},{"key":"toDate","value":"{{financialYear}}-05-31"},{"key":"pageSize","value":"200"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"balances\": {\n      \"opening\": {\n        \"type\": \"Synthetic type\",\n        \"date\": \"2026-05-10\",\n        \"date_raw\": \"2026-05-10\",\n        \"voucher_no\": \"Synthetic voucher_no\",\n        \"particulars\": \"Synthetic particulars\",\n        \"cash_signed\": 0,\n        \"bank_signed\": 0,\n        \"bank_od_signed\": 0,\n        \"party_signed\": 0,\n        \"others_signed\": 0,\n        \"cash\": 0,\n        \"bank\": 0,\n        \"bank_od\": 0,\n        \"party\": 0,\n        \"others\": 0\n      },\n      \"closing\": {\n        \"type\": \"Synthetic type\",\n        \"date\": \"2026-05-10\",\n        \"date_raw\": \"2026-05-10\",\n        \"voucher_no\": \"Synthetic voucher_no\",\n        \"particulars\": \"Synthetic particulars\",\n        \"cash_signed\": 0,\n        \"bank_signed\": 0,\n        \"bank_od_signed\": 0,\n        \"party_signed\": 0,\n        \"others_signed\": 0,\n        \"cash\": 0,\n        \"bank\": 0,\n        \"bank_od\": 0,\n        \"party\": 0,\n        \"others\": 0\n      }\n    },\n    \"rows\": []\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.day-end.detailed\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"ab070938cac63727\",\n      \"tables\": [\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Folio1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"2675108e-d1d4-4dc2-895e-95a407335337"}],"id":"a4eaba31-2dbf-4dda-94a9-b5cdd1e28578","description":"<p>Snapshot reads of the reports in the live family <em>Ledgers, analytics and summaries</em> (9); each request names its live equivalent.</p>\n<ul>\n<li><strong>Customer ledger</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/customers/{customerId}/ledger</code></li>\n<li><strong>Account monthly summary</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/accounts/monthly-summary</code></li>\n<li><strong>Account consolidated summary</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/accounts/consolidated-summary</code></li>\n<li><strong>Item ledger</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/items/{productId}/ledger</code></li>\n<li><strong>Sales analysis — one item</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/sales-analysis/items/{productId}</code></li>\n<li><strong>Sales analysis — one customer</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/sales-analysis/customers/{customerId}</code></li>\n<li><strong>Customer product analytics</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/customers/{customerId}/product-analytics</code></li>\n<li><strong>Day-end summary</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/day-end/summary</code></li>\n<li><strong>Detailed day-end report</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/day-end/detailed</code></li>\n</ul>\n","_postman_id":"a4eaba31-2dbf-4dda-94a9-b5cdd1e28578","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Registers, orders and invoices","item":[{"name":"Sales register","id":"e0249920-6dc5-4453-9d3d-6956b74e2dae","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/registers/sales?fromDate={{financialYear}}-05-01&toDate={{financialYear}}-05-31&pageSize=100","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/registers/sales</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.registers.sales</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/sales-register</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ rows: array of { date, voucher_code, voucher_type_id, voucher_number, customer_id, customer_name, gst_number, mobile_number, sale_type_id, sale_type_name, total_amount, sale_amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, other_amount, material_center_id, material_center_name, receipt_amount, status }, summary: { total_amount_total, sale_amount_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total, other_amount_total, receipt_amount_total, total_tax_amount_total } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, fromDate, toDate (as applied), source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (a repeated voucher code; differing address rows of a party); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Sales (voucher type 9) and sales returns (type 3), the returns negated once (every amount × −1). Cancelled vouchers stay in the rows and the summary with status \"Cancelled\" (Tran1.Cancelled or VchCancelled true, as the twin's shared rule); otherwise \"Pending\" when the voucher made a bill reference (Tran3 record type 1, method 1) for its party, else \"N/A\". GST is voucher-level (VchGSTSumItemWise record type 0 or NULL): IGST where TaxRate1 is 0, else CGST = TaxAmt and SGST = TaxAmt1. other_amount = Σ Tran2.Value3 of record type 3. The settled amount = Σ |Tran3.Value1| of method-2 allocations against the voucher's own reference codes and party (no FIFO). A voucher with several reference codes is one row; several differing address rows of a party, or a repeated voucher code, are refused (422) instead of repeating a row. Ordered by date, voucher number (binary), voucher code. The range is the twin's: neither date = the whole financial year, one date alone = that one day, both = the range (inside the year, fromDate not after toDate); a voucher counts by its date read as the twin reads BUSY date text. Every row of the range and data.summary over all of them are computed before the page is cut, so the summary is the same on every page. Paged (the twin pages the same whole list); amounts are BUSY's doubles summed in the twin's order and rounded with SQLite ROUND(x, 2) on the exact binary value.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/registers/sales?fromDate=2025-05-01&amp;toDate=2025-05-31&amp;pageSize=100\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","registers","sales"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-05-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"toDate","value":"{{financialYear}}-05-31"},{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"100"}],"variable":[]}},"response":[{"id":"c257b047-9b7c-fa6e-2eef-24eaf8836d71","name":"SYNTHETIC — 200 snapshot.registers.sales (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/registers/sales?fromDate={{financialYear}}-05-01&toDate={{financialYear}}-05-31&pageSize=100","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","registers","sales"],"query":[{"key":"fromDate","value":"{{financialYear}}-05-01"},{"key":"toDate","value":"{{financialYear}}-05-31"},{"key":"pageSize","value":"100"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"rows\": [],\n    \"summary\": {\n      \"total_amount_total\": 0,\n      \"sale_amount_total\": 0,\n      \"taxable_amount_total\": 0,\n      \"igst_amount_total\": \"Synthetic igst_amount_total\",\n      \"cgst_amount_total\": \"Synthetic cgst_amount_total\",\n      \"sgst_amount_total\": \"Synthetic sgst_amount_total\",\n      \"other_amount_total\": 0,\n      \"receipt_amount_total\": 0,\n      \"total_tax_amount_total\": 0\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.registers.sales\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"71646d39f6c8fa4a\",\n      \"tables\": [\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"VchGSTSumItemWise\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran3\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"e0249920-6dc5-4453-9d3d-6956b74e2dae"},{"name":"Purchase register","id":"9655ec56-5a81-4faa-bddb-588336d238e8","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/registers/purchase?fromDate={{financialYear}}-05-01&toDate={{financialYear}}-05-31","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/registers/purchase</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.registers.purchase</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/purchase-register</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ rows: array of { date, voucher_code, voucher_type_id, voucher_number, account_id, account_name, gst_number, mobile_number, purchase_type_id, purchase_type_name, total_amount, purchase_amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, other_amount, material_center_id, material_center_name, payment_amount, status }, summary: { total_amount_total, purchase_amount_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total, other_amount_total, payment_amount_total, total_tax_amount_total } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, fromDate, toDate (as applied), source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (a repeated voucher code; differing address rows of a party); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Purchases (voucher type 2) and purchase returns (type 10), the returns negated once (every amount × −1). Cancelled vouchers stay in the rows and the summary with status \"Cancelled\" (Tran1.Cancelled or VchCancelled true, as the twin's shared rule); otherwise \"Pending\" when the voucher made a bill reference (Tran3 record type 1, method 1) for its party, else \"N/A\". GST is voucher-level (VchGSTSumItemWise record type 0 or NULL): IGST where TaxRate1 is 0, else CGST = TaxAmt and SGST = TaxAmt1. other_amount = Σ Tran2.Value3 of record type 3. The settled amount = Σ |Tran3.Value1| of method-2 allocations against the voucher's own reference codes and party (no FIFO). A voucher with several reference codes is one row; several differing address rows of a party, or a repeated voucher code, are refused (422) instead of repeating a row. Ordered by date, voucher number (binary), voucher code. The range is the twin's: neither date = the whole financial year, one date alone = that one day, both = the range (inside the year, fromDate not after toDate); a voucher counts by its date read as the twin reads BUSY date text. Every row of the range and data.summary over all of them are computed before the page is cut, so the summary is the same on every page. Paged (the twin pages the same whole list); amounts are BUSY's doubles summed in the twin's order and rounded with SQLite ROUND(x, 2) on the exact binary value.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/registers/purchase?fromDate=2025-05-01&amp;toDate=2025-05-31\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","registers","purchase"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-05-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"toDate","value":"{{financialYear}}-05-31"}],"variable":[]}},"response":[{"id":"cf37d5ec-2be0-e4a0-6353-8ef6d9905f77","name":"SYNTHETIC — 200 snapshot.registers.purchase (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/registers/purchase?fromDate={{financialYear}}-05-01&toDate={{financialYear}}-05-31","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","registers","purchase"],"query":[{"key":"fromDate","value":"{{financialYear}}-05-01"},{"key":"toDate","value":"{{financialYear}}-05-31"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"rows\": [],\n    \"summary\": {\n      \"total_amount_total\": 0,\n      \"purchase_amount_total\": 0,\n      \"taxable_amount_total\": 0,\n      \"igst_amount_total\": \"Synthetic igst_amount_total\",\n      \"cgst_amount_total\": \"Synthetic cgst_amount_total\",\n      \"sgst_amount_total\": \"Synthetic sgst_amount_total\",\n      \"other_amount_total\": 0,\n      \"payment_amount_total\": 0,\n      \"total_tax_amount_total\": 0\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.registers.purchase\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"71646d39f6c8fa4a\",\n      \"tables\": [\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"VchGSTSumItemWise\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran3\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"9655ec56-5a81-4faa-bddb-588336d238e8"},{"name":"Sales return / credit note register","id":"bc7f1c69-59e8-4980-af45-82c986ec4a94","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/registers/sales-return?fromDate={{financialYear}}-04-01&toDate={{financialYear}}-09-30","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/registers/sales-return</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.registers.sales-return</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/sales-return-crnote-register</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ rows: array of { date, voucher_code, voucher_type_id, voucher_number, customer_id, customer_name, gst_number, mobile_number, sale_type_id, sale_type_name, total_amount, sale_amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, other_amount, material_center_id, material_center_name, receipt_amount, status }, summary: { total_amount_total, sale_amount_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total, other_amount_total, receipt_amount_total, total_tax_amount_total } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, fromDate, toDate (as applied), source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (a repeated voucher code; differing address rows of a party); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Sales returns (voucher type 3) with their amounts as stored (not negated). Cancelled vouchers stay in the rows and the summary with status \"Cancelled\" (Tran1.Cancelled or VchCancelled true, as the twin's shared rule); otherwise \"Pending\" when the voucher made a bill reference (Tran3 record type 1, method 1) for its party, else \"N/A\". GST is voucher-level (VchGSTSumItemWise record type 0 or NULL): IGST where TaxRate1 is 0, else CGST = TaxAmt and SGST = TaxAmt1. other_amount = Σ Tran2.Value3 of record type 3. The settled amount = Σ |Tran3.Value1| of method-2 allocations against the voucher's own reference codes and party (no FIFO). A voucher with several reference codes is one row; several differing address rows of a party, or a repeated voucher code, are refused (422) instead of repeating a row. Ordered by date, voucher number (binary), voucher code. The range is the twin's: neither date = the whole financial year, one date alone = that one day, both = the range (inside the year, fromDate not after toDate); a voucher counts by its date read as the twin reads BUSY date text. Every row of the range and data.summary over all of them are computed before the page is cut, so the summary is the same on every page. Paged (the twin pages the same whole list); amounts are BUSY's doubles summed in the twin's order and rounded with SQLite ROUND(x, 2) on the exact binary value.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/registers/sales-return?fromDate=2025-04-01&amp;toDate=2026-03-31\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","registers","sales-return"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-04-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"toDate","value":"{{financialYear}}-09-30"}],"variable":[]}},"response":[{"id":"b8cab5ea-e60e-0b70-8fdd-834aeaeb3b4d","name":"SYNTHETIC — 200 snapshot.registers.sales-return (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/registers/sales-return?fromDate={{financialYear}}-04-01&toDate={{financialYear}}-09-30","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","registers","sales-return"],"query":[{"key":"fromDate","value":"{{financialYear}}-04-01"},{"key":"toDate","value":"{{financialYear}}-09-30"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"rows\": [],\n    \"summary\": {\n      \"total_amount_total\": 0,\n      \"sale_amount_total\": 0,\n      \"taxable_amount_total\": 0,\n      \"igst_amount_total\": \"Synthetic igst_amount_total\",\n      \"cgst_amount_total\": \"Synthetic cgst_amount_total\",\n      \"sgst_amount_total\": \"Synthetic sgst_amount_total\",\n      \"other_amount_total\": 0,\n      \"receipt_amount_total\": 0,\n      \"total_tax_amount_total\": 0\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.registers.sales-return\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"71646d39f6c8fa4a\",\n      \"tables\": [\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"VchGSTSumItemWise\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran3\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"bc7f1c69-59e8-4980-af45-82c986ec4a94"},{"name":"Purchase return / debit note register","id":"4a908561-2c8a-4e97-a1d4-568bb08a5238","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/registers/purchase-return","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/registers/purchase-return</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.registers.purchase-return</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/purchase-return-drnote-register</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ rows: array of { date, voucher_code, voucher_type_id, voucher_number, account_id, account_name, gst_number, mobile_number, purchase_type_id, purchase_type_name, total_amount, purchase_amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, other_amount, material_center_id, material_center_name, payment_amount, status }, summary: { total_amount_total, purchase_amount_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total, other_amount_total, payment_amount_total, total_tax_amount_total } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, fromDate, toDate (as applied), source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (a repeated voucher code; differing address rows of a party); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Purchase returns (voucher type 10) with their amounts as stored (not negated). Cancelled vouchers stay in the rows and the summary with status \"Cancelled\" (Tran1.Cancelled or VchCancelled true, as the twin's shared rule); otherwise \"Pending\" when the voucher made a bill reference (Tran3 record type 1, method 1) for its party, else \"N/A\". GST is voucher-level (VchGSTSumItemWise record type 0 or NULL): IGST where TaxRate1 is 0, else CGST = TaxAmt and SGST = TaxAmt1. other_amount = Σ Tran2.Value3 of record type 3. The settled amount = Σ |Tran3.Value1| of method-2 allocations against the voucher's own reference codes and party (no FIFO). A voucher with several reference codes is one row; several differing address rows of a party, or a repeated voucher code, are refused (422) instead of repeating a row. Ordered by date, voucher number (binary), voucher code. The range is the twin's: neither date = the whole financial year, one date alone = that one day, both = the range (inside the year, fromDate not after toDate); a voucher counts by its date read as the twin reads BUSY date text. Every row of the range and data.summary over all of them are computed before the page is cut, so the summary is the same on every page. Paged (the twin pages the same whole list); amounts are BUSY's doubles summed in the twin's order and rounded with SQLite ROUND(x, 2) on the exact binary value.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/registers/purchase-return\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","registers","purchase-return"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"e0ecc450-697c-298c-1a11-645f40638852","name":"SYNTHETIC — 200 snapshot.registers.purchase-return (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/registers/purchase-return"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"rows\": [],\n    \"summary\": {\n      \"total_amount_total\": 0,\n      \"purchase_amount_total\": 0,\n      \"taxable_amount_total\": 0,\n      \"igst_amount_total\": \"Synthetic igst_amount_total\",\n      \"cgst_amount_total\": \"Synthetic cgst_amount_total\",\n      \"sgst_amount_total\": \"Synthetic sgst_amount_total\",\n      \"other_amount_total\": 0,\n      \"payment_amount_total\": 0,\n      \"total_tax_amount_total\": 0\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.registers.purchase-return\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"71646d39f6c8fa4a\",\n      \"tables\": [\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"VchGSTSumItemWise\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran3\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"4a908561-2c8a-4e97-a1d4-568bb08a5238"},{"name":"Payment register","id":"f9d64e9d-188c-4f87-84fc-9ed6e232a295","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/registers/payment?fromDate={{financialYear}}-06-01&toDate={{financialYear}}-06-30","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/registers/payment</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.registers.payment</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/payment-register</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ rows: array of { date, voucher_code, voucher_type_id, voucher_number, gst_nature_id, gst_nature, mode_id, mode_name, account_id, account_name, mobile_number, amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, short_narration, instrument_type_id, instrument_type, instrument_number }, summary: { amount_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, fromDate, toDate (as applied), source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (a repeated voucher code; differing mobile rows of an account); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Payment vouchers (type 19, Tran1.TranType not 1, dated in the range, with at least one Tran2 line of type 19 whose TranType is not 1 dated in the range): one row per paid account line (Tran2 record type 1, Value1 &lt; 0), amount = |Value1|; the mode is the voucher's first account line with Value1 &gt; 0 (by line number, then the line's own values). The voucher's GST is repeated on each of its lines and the summary adds the line values, as the twin and the reference. instrument_type from Tran2.I2: 1 Cheque, 2 NEFT, 3 RTGS, 4 IMPS, 5 UPI, 0 blank, any other code as its number. gst_nature = Tran1.GSTRecType (\"Not Applicable\" for 0). Cancelled vouchers are not marked or left out (the twin and the reference read no cancellation flag here). Ordered by date, voucher number, voucher code, then the line. The range is the twin's: neither date = the whole financial year, one date alone = that one day, both = the range (inside the year, fromDate not after toDate); a voucher counts by its date read as the twin reads BUSY date text. Every row of the range and data.summary over all of them are computed before the page is cut, so the summary is the same on every page. Paged (the twin pages the same whole list); amounts are BUSY's doubles summed in the twin's order and rounded with SQLite ROUND(x, 2) on the exact binary value.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/registers/payment?fromDate=2025-06-01&amp;toDate=2025-06-30\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","registers","payment"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-06-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"toDate","value":"{{financialYear}}-06-30"}],"variable":[]}},"response":[{"id":"88e497a7-bd98-8d7f-8250-85096cdc8d74","name":"SYNTHETIC — 200 snapshot.registers.payment (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/registers/payment?fromDate={{financialYear}}-06-01&toDate={{financialYear}}-06-30","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","registers","payment"],"query":[{"key":"fromDate","value":"{{financialYear}}-06-01"},{"key":"toDate","value":"{{financialYear}}-06-30"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"rows\": [],\n    \"summary\": {\n      \"amount_total\": 0,\n      \"taxable_amount_total\": 0,\n      \"igst_amount_total\": \"Synthetic igst_amount_total\",\n      \"cgst_amount_total\": \"Synthetic cgst_amount_total\",\n      \"sgst_amount_total\": \"Synthetic sgst_amount_total\"\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.registers.payment\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"f56dbfaf12ab8979\",\n      \"tables\": [\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"VchGSTSumItemWise\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"f9d64e9d-188c-4f87-84fc-9ed6e232a295"},{"name":"Receipt register","id":"ba505ab5-888a-4ea2-872d-3a4ae3e6dfad","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/registers/receipt?fromDate={{financialYear}}-06-15","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/registers/receipt</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.registers.receipt</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/receipt-register</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ rows: array of { date, voucher_code, voucher_type_id, voucher_number, gst_nature_id, gst_nature, mode_id, mode_name, account_id, account_name, mobile_number, amount, short_narration, instrument_type_id, instrument_type, instrument_number }, summary: { amount_total } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, fromDate, toDate (as applied), source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (a repeated voucher code; differing mobile rows of an account); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Receipt vouchers (type 14), the payment register's rules with the signs mirrored: one row per received account line (Value1 &gt; 0), the mode the first line with Value1 &lt; 0; no GST columns. Instrument names as the payment register. The range is the twin's: neither date = the whole financial year, one date alone = that one day, both = the range (inside the year, fromDate not after toDate); a voucher counts by its date read as the twin reads BUSY date text. Every row of the range and data.summary over all of them are computed before the page is cut, so the summary is the same on every page. Paged (the twin pages the same whole list); amounts are BUSY's doubles summed in the twin's order and rounded with SQLite ROUND(x, 2) on the exact binary value.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/registers/receipt?fromDate=2025-06-15\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","registers","receipt"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-06-15"}],"variable":[]}},"response":[{"id":"a39cd0ed-3461-4050-19d4-221d38e894ed","name":"SYNTHETIC — 200 snapshot.registers.receipt (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/registers/receipt?fromDate={{financialYear}}-06-15","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","registers","receipt"],"query":[{"key":"fromDate","value":"{{financialYear}}-06-15"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"rows\": [],\n    \"summary\": {\n      \"amount_total\": 0\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.registers.receipt\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"b4548c5456bf259c\",\n      \"tables\": [\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"ba505ab5-888a-4ea2-872d-3a4ae3e6dfad"},{"name":"Journal register","id":"b282b49a-972a-4c61-91c9-e28b9396f884","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/registers/journal?pageSize=200","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/registers/journal</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.registers.journal</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/journal-register</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ rows: array of { date, voucher_code, voucher_type_id, voucher_number, line_srno, voucher_line_no, gst_nature_id, gst_nature, account_id, account_name, mobile_number, debit_amount, credit_amount, taxable_amount, igst_amount, cgst_amount, sgst_amount, short_narration, instrument_type_id, instrument_type, instrument_number }, summary: { debit_total, credit_total, taxable_amount_total, igst_amount_total, cgst_amount_total, sgst_amount_total } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, fromDate, toDate (as applied), source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (a repeated voucher code; differing mobile rows of an account); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Every account line (Tran2 record type 1) of voucher type 16 dated in the range, one row per line: debit = |Value1| when negative, credit = Value1 when positive; voucher_line_no numbers the voucher's lines in the range in line order; voucher_number = the line's VchNo, else the header's; gst_nature from the header; the voucher's GST repeated on each line (the summary adds the line values, as the twin). instrument_type from Tran2.I2 with the journal's own map, kept as the reference has it: 1 RTGS, 2 NEFT, 3 Cheque, 4 IMPS, 5 UPI (it differs from the payment map). Ordered by date, voucher number, voucher code, line number, position. The range is the twin's: neither date = the whole financial year, one date alone = that one day, both = the range (inside the year, fromDate not after toDate); a voucher counts by its date read as the twin reads BUSY date text. Every row of the range and data.summary over all of them are computed before the page is cut, so the summary is the same on every page. Paged (the twin pages the same whole list); amounts are BUSY's doubles summed in the twin's order and rounded with SQLite ROUND(x, 2) on the exact binary value.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/registers/journal?pageSize=200\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","registers","journal"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"200"}],"variable":[]}},"response":[{"id":"697f00e3-9081-79f4-2f3a-7dde3235e538","name":"SYNTHETIC — 200 snapshot.registers.journal (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/registers/journal?pageSize=200","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","registers","journal"],"query":[{"key":"pageSize","value":"200"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"rows\": [],\n    \"summary\": {\n      \"debit_total\": 0,\n      \"credit_total\": 0,\n      \"taxable_amount_total\": 0,\n      \"igst_amount_total\": \"Synthetic igst_amount_total\",\n      \"cgst_amount_total\": \"Synthetic cgst_amount_total\",\n      \"sgst_amount_total\": \"Synthetic sgst_amount_total\"\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.registers.journal\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"f56dbfaf12ab8979\",\n      \"tables\": [\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"VchGSTSumItemWise\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"b282b49a-972a-4c61-91c9-e28b9396f884"},{"name":"Contra register","id":"98ea6a98-7491-4db6-a564-bc6ccd33ec2e","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/registers/contra","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/registers/contra</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.registers.contra</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/contra-register</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ rows: array of { date, voucher_code, voucher_type_id, voucher_number, line_srno, voucher_line_no, account_id, account_name, mobile_number, debit_amount, credit_amount, short_narration, instrument_type_id, instrument_type, instrument_number }, summary: { debit_total, credit_total } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, fromDate, toDate (as applied), source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (differing mobile rows of an account); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Every account line (Tran2 record type 1) of voucher type 15 dated in the range, as the journal register without GST; voucher_number = the line's VchNo; instrument_type with the journal's map plus 9 IMPS and 11 Transfer. The range is the twin's: neither date = the whole financial year, one date alone = that one day, both = the range (inside the year, fromDate not after toDate); a voucher counts by its date read as the twin reads BUSY date text. Every row of the range and data.summary over all of them are computed before the page is cut, so the summary is the same on every page. Paged (the twin pages the same whole list); amounts are BUSY's doubles summed in the twin's order and rounded with SQLite ROUND(x, 2) on the exact binary value.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/registers/contra\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","registers","contra"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"2c594c8a-111f-7a08-6d8d-f5686eed6a92","name":"SYNTHETIC — 200 snapshot.registers.contra (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/registers/contra"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"rows\": [],\n    \"summary\": {\n      \"debit_total\": 0,\n      \"credit_total\": 0\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.registers.contra\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"eb5b723d5fd7f75d\",\n      \"tables\": [\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"98ea6a98-7491-4db6-a564-bc6ccd33ec2e"},{"name":"Pending sales orders","id":"0f6e1b8a-19ef-483b-b90c-d698c0468a17","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sales-orders/pending?customerId={{customerId}}&statusField=OF1","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/sales-orders/pending</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.sales-orders.pending</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/pending-sales-orders</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>customerId</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { sales_order_refcode, reference_no, order_date, due_date, customer_id, customer_name, product_id, product_name, unit_id, unit_name, status_id, status, total_qty, pending_qty, product_stock }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, customerId, referenceNumberApplied, statusField, source, snapshot, filters (never the reference number), pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (several differing address, billing or other-information rows of a record in the answer) — with statusField; 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>The customer's order lines: Tran3 record type 4, method 1, voucher type 12, plus carried-forward orders (type 1, code −1200). Pending quantity = the exact RefCode lifecycle: the ascending sum of every Tran3 row of that reference code, leaving out a row whose party (its own when not 0, else its voucher header's) is another known customer (no FIFO; never another customer's dispatch); only references still pending (&gt; 0 once rounded) count. Cancelled vouchers are neither left out nor labelled (the reference has no rule here). One row per pending order item, grouped as the reference (reference code, number, date, due date, item, status): total_qty = the ordered quantity (rounded to 2); product_stock = Σ Tran2.Value1 outside voucher types 12, 25, 26, 13 + Σ Folio1.D1, rounded to 2. Product name: the least Help1 name row (NameOrAlias 1) of the product, else its name. Dates are SQLite DATE() of BUSY's text. referenceNumber (optional, trimmed, at most 200 characters, blank = none) matches an order whose trimmed number or reference code equals it exactly; it is never echoed or logged (metadata.referenceNumberApplied is true/false only). statusField names one of BUSY's ten optional voucher fields (OF1 … OF10, trimmed, any case; blank = none): the status is that field of the order voucher's VchOtherInfo row read as SQLite CAST(TRIM(x) AS INTEGER) (blank = no status) and that master's name; with it, VchOtherInfo is read and a sales-order voucher anywhere in the year with several differing VchOtherInfo rows refuses the answer (the twin). metadata.statusField echoes the canonical name. Ordered by the raw date, the raw number, product name, then the row's own keys; the page is cut after everything is computed.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>customerId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>yes</td>\n<td>whole number from 1 to 2147483647: the customer's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>referenceNumber</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>trimmed, at most 200 characters; blank = none; never echoed in the answer or logged (metadata.referenceNumberApplied says whether one was applied)</td>\n<td>none</td>\n</tr>\n<tr>\n<td><code>statusField</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>one of OF1 to OF10 (trimmed, any case): the order optional field read as the status; blank = none</td>\n<td>none</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/sales-orders/pending?customerId=1001&amp;statusField=OF1\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","sales-orders","pending"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>whole number from 1 to 2147483647: the customer's code</p>\n","type":"text/plain"},"key":"customerId","value":"{{customerId}}"},{"description":{"content":"<p>one of OF1 to OF10 (trimmed, any case): the order optional field read as the status; blank = none</p>\n","type":"text/plain"},"key":"statusField","value":"OF1"}],"variable":[]}},"response":[{"id":"8c5c7ad2-b4bc-21a0-dc89-b80bd2eb500d","name":"SYNTHETIC — 200 snapshot.sales-orders.pending (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sales-orders/pending?customerId={{customerId}}&statusField=OF1","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","sales-orders","pending"],"query":[{"key":"customerId","value":"{{customerId}}"},{"key":"statusField","value":"OF1"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.sales-orders.pending\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"6272b4ce0ef4aa0a\",\n      \"tables\": [\n        {\n          \"table\": \"Tran3\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Folio1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"0f6e1b8a-19ef-483b-b90c-d698c0468a17"},{"name":"Pending sales-order vouchers","id":"89b37ab0-bb91-4b8b-a69a-9224680a7f46","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sales-orders/pending-vouchers?customerId={{customerId}}","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/sales-orders/pending-vouchers</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.sales-orders.pending-vouchers</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/pending-sales-order-vouchers</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>customerId</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { sales_order_refcode, sales_order_vch_code, sales_order_number, order_date, due_date, customer_id, customer_name, material_center_id, material_center_name, status_id, status, total_ordered_qty, total_dispatched_qty, total_pending_qty }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, customerId, statusField, source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (several differing address, billing or other-information rows of a record in the answer) — with statusField; 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>The customer's order lines: Tran3 record type 4, method 1, voucher type 12, plus carried-forward orders (type 1, code −1200). Pending quantity = the exact RefCode lifecycle: the ascending sum of every Tran3 row of that reference code, leaving out a row whose party (its own when not 0, else its voucher header's) is another known customer (no FIFO; never another customer's dispatch); only references still pending (&gt; 0 once rounded) count. Cancelled vouchers are neither left out nor labelled (the reference has no rule here). The pending references summed per voucher (trimmed number, voucher code and type): total_ordered_qty and total_pending_qty the rounded sums of the references' rounded quantities, total_dispatched_qty = ordered − pending; the least reference code and dates; the voucher's material centre (Tran1.MasterCode2 of the order voucher). The reference grouped by number and customer only; different vouchers that share a number stay apart (the twin). statusField names one of BUSY's ten optional voucher fields (OF1 … OF10, trimmed, any case; blank = none): the status is that field of the order voucher's VchOtherInfo row read as SQLite CAST(TRIM(x) AS INTEGER) (blank = no status) and that master's name; with it, VchOtherInfo is read and a sales-order voucher anywhere in the year with several differing VchOtherInfo rows refuses the answer (the twin). metadata.statusField echoes the canonical name. Ordered by order date, number, voucher code, reference code.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>customerId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>yes</td>\n<td>whole number from 1 to 2147483647: the customer's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>statusField</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>one of OF1 to OF10 (trimmed, any case): the order optional field read as the status; blank = none</td>\n<td>none</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/sales-orders/pending-vouchers?customerId=1001\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","sales-orders","pending-vouchers"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>whole number from 1 to 2147483647: the customer's code</p>\n","type":"text/plain"},"key":"customerId","value":"{{customerId}}"}],"variable":[]}},"response":[{"id":"a0da1522-ef09-7dc9-fca8-0bf4038feb63","name":"SYNTHETIC — 200 snapshot.sales-orders.pending-vouchers (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sales-orders/pending-vouchers?customerId={{customerId}}","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","sales-orders","pending-vouchers"],"query":[{"key":"customerId","value":"{{customerId}}"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.sales-orders.pending-vouchers\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"6d88de22a379fddb\",\n      \"tables\": [\n        {\n          \"table\": \"Tran3\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"89b37ab0-bb91-4b8b-a69a-9224680a7f46"},{"name":"Sale invoices","id":"f97f0aa1-62ed-4bf6-a5e9-d4ce39b758f1","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sales/invoices?startDate={{financialYear}}-05-01&endDate={{financialYear}}-05-31&customerId={{customerId}}","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/sales/invoices</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.sales.invoices</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/all-sale-invoices</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>startDate and endDate (both inside the year, startDate not after endDate)</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { vch_code, date, invoice_no, material_center_id, material_center, material_center_group_id, material_center_group, sale_type_id, sale_type_name, customer_id, customer_name, customer_print_name, customer_group_id, customer_group_name, gst_number, mobile_number, whatsapp_number, station, state, billing_name, billing_gst_no, billing_address, salesman_id, salesman_name, salesman_mobile_number, salesman_whatsapp_number, total_amount, grand_total, bill_reference_code, bill_reference_count, payment_status, is_paid, paid_amount, pending_amount, transport, vehicle_no, eway_no, einv_no, last_action_time, processed_by }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, startDate, endDate, customerId, materialCenterId, materialCenterGroupId, source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (several differing address, billing or other-information rows of a record in the answer); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>startDate and endDate are required (YYYY-MM-DD inside the year, start not after end; the twin's rule). Sale invoices (Tran1 type 9) whose BUSY date lies in the range, optionally of one customer, one material centre, or one material-centre group (the centre's parent group; the centre must be a material centre). The reference's 40 members in its order and types: date DD-MM-YYYY; total_amount and grand_total two-decimal texts of VchAmtBaseCur / VchSalePurcAmt (the twin's reading of the reference's printf('%.2f'): the stored double's shortest decimal text rounded half away from zero — 2.675 → \"2.68\"; SQLite 3.53's own printf would give \"2.67\"); customer, group, address, billing, salesman, transport, vehicle and e-way (VchOtherInfo.Form31No), e-invoice (Tran1.EInvAckNo). Payment status from the invoice's own bill references (Tran3 type 9, record type 1, method 1) for its party only: Not Tracked (none), Paid (pending 0), Partially Paid (pending below |total|), Unpaid; pending_amount = Σ per reference |Σ that party's rows of the reference code|, rounded; paid_amount = |total| − pending when larger, else 0. The latest action is the latest CheckList voucher action (type 2) by time (SQLite strftime('%d-%m-%Y %H:%M')), ties by action then user; master actions (type 1) never join. Cancelled invoices stay (the reference has no cancellation rule here). A sale voucher anywhere in the year with several differing VchOtherInfo rows, or a selected invoice whose party, billing or salesman has several differing rows, refuses the answer (the twin). Ordered by the raw date text descending, then voucher code descending.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>startDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>see Required</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>endDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>see Required</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>customerId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the customer's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>materialCenterId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the material centre</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>materialCenterGroupId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the material-centre group</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/sales/invoices?startDate=2025-05-01&amp;endDate=2025-05-31&amp;customerId=1001\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","sales","invoices"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent</p>\n","type":"text/plain"},"key":"startDate","value":"{{financialYear}}-05-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent</p>\n","type":"text/plain"},"key":"endDate","value":"{{financialYear}}-05-31"},{"description":{"content":"<p>whole number from 1 to 2147483647: the customer's code</p>\n","type":"text/plain"},"key":"customerId","value":"{{customerId}}"}],"variable":[]}},"response":[{"id":"fcd9a771-5457-79ba-cda7-00be6cd6ba7f","name":"SYNTHETIC — 200 snapshot.sales.invoices (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sales/invoices?startDate={{financialYear}}-05-01&endDate={{financialYear}}-05-31&customerId={{customerId}}","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","sales","invoices"],"query":[{"key":"startDate","value":"{{financialYear}}-05-01"},{"key":"endDate","value":"{{financialYear}}-05-31"},{"key":"customerId","value":"{{customerId}}"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.sales.invoices\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"48fb61732cae1ff3\",\n      \"tables\": [\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran3\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"CheckList\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"BillingDet\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"VchOtherInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"f97f0aa1-62ed-4bf6-a5e9-d4ce39b758f1"},{"name":"Sale invoice items","id":"9db45113-4559-45b6-936d-b5fae9678e6b","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sales/invoices/{{salesInvoiceVoucherId}}/items","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/sales/invoices/{voucherId}/items</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.sales.invoices.items</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/sale-invoice-products</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>path: voucherId</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>not paged</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { voucher_id, date, invoice_no, customer_id, customer_name, customer_alias, material_center_id, material_center_name, sale_type_id, sale_type_name, product_id, product_name, product_alias, product_print_name, product_group_id, product_group_name, product_hsn_code, product_mrp, quantity, unit_id, unit_name, base_rate, sale_rate, taxable_value, gst_percentage, gst_amount, cgst_percentage, cgst_amount, sgst_percentage, sgst_amount, igst_percentage, igst_amount, total_amount }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, voucherId, source, snapshot, filters, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 NOT_FOUND (field voucherId: not a sale invoice, unknown, or without item lines); 422 BUSY_DATA_INCONSISTENT (a repeated voucher header); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>The item lines (Tran2 record type 2) of one sale invoice (type 9): MRP, quantity (3 decimals), base rate (taxable ÷ quantity) and sale rate (total ÷ quantity), taxable value, total and GST per line. The GST rows (record type 0 or NULL) of one item line are one: amounts summed, rates and location type the largest (absolute values); location type 0 = CGST (TaxRate / TaxAmt) + SGST (TaxRate1 / TaxAmt1), else IGST (their sum); no GST row = 0, as the reference. Ordered by line number, item, then the line's own values. A voucher that is not a sale invoice, an unknown voucher or an invoice without item lines is 404 (no value echoed). Not paged, as the twin and the reference.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>voucherId</code></td>\n<td>path</td>\n<td>integer</td>\n<td>yes</td>\n<td>whole number from 1 to 2147483647: the voucher's code</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/sales/invoices/5001/items\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","sales","invoices","{{salesInvoiceVoucherId}}","items"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"5f0d3744-7470-cc94-4727-7e33ae20e43b","name":"SYNTHETIC — 200 snapshot.sales.invoices.items (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sales/invoices/{{salesInvoiceVoucherId}}/items"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.sales.invoices.items\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"e7d75256604200ef\",\n      \"tables\": [\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"VchGSTSumItemWise\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"9db45113-4559-45b6-936d-b5fae9678e6b"},{"name":"Sale vouchers with items","id":"41584756-ccc0-43a2-92c1-18384afbe08e","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sales/vouchers-with-items?fromDate={{financialYear}}-05-01&toDate={{financialYear}}-05-07&pageSize=50","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/sales/vouchers-with-items</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.sales.vouchers-with-items</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/list-sale-vouchers-with-items</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ vouchers: array of { voucher_code, voucher_number, date, voucher_type_id, approval_status, rejection_status, customer_id, customer_name, customer_state, customer_gst_no, customer_mobile_number, customer_whatsapp_number, billing_gst_no, billing_mobile_number, material_center_id, material_center_name, total_quantity, total_amount, items: array of { sr_no, product_id, product_name, product_group_id, product_group_name, purchase_date, unit_id, unit_name, quantity, price, amount, cgst_percent, cgst_amount, sgst_percent, sgst_amount, igst_percent, igst_amount, gst_percent, gst_amount, list_price, net_price, amount_before_discount } }, summary: { total_quantity, total_amount, item_row_count, voucher_count } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, fromDate, toDate (as applied), source, snapshot, filters, pagination (counted in vouchers), rowCount (vouchers), elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (several differing address, billing or other-information rows of a record in the answer); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>fromDate / toDate: the registers' rule (neither = the whole year, one alone = that one day, both = the range; inside the year). Every sale item line (Tran2 record type 2, type 9) whose BUSY line date lies in the range, with its header (same code and type), nested per voucher in the reference's order (date, number, voucher code, line, item, then the line's rounded values); vouchers in order of first appearance, the header from their first line. Customer = the line's CM1 when not 0, else the header's party; names are the least Help1 name row (any master type), else the print name, else the name; GST record type 0 exactly (several rows of one line are one). Item values are the reference's (rounded to 2), voucher totals and the summary are the controller's roundToTwo running sums. <strong>Pages are counted in vouchers and never split a voucher's items; the summary (total_quantity, total_amount, item_row_count, voucher_count) covers the whole range, never one page</strong>; pagination.totalRows counts vouchers. A customer of any line in the range with several differing address rows, or a voucher with several differing billing rows, refuses the answer (the twin).</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/sales/vouchers-with-items?fromDate=2025-05-01&amp;toDate=2025-05-07&amp;pageSize=50\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","sales","vouchers-with-items"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-05-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"toDate","value":"{{financialYear}}-05-07"},{"description":{"content":"<p>rows per page, a whole number from 1 to 500</p>\n","type":"text/plain"},"key":"pageSize","value":"50"}],"variable":[]}},"response":[{"id":"ccd49011-41f8-53b7-b816-0e25a02df344","name":"SYNTHETIC — 200 snapshot.sales.vouchers-with-items (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sales/vouchers-with-items?fromDate={{financialYear}}-05-01&toDate={{financialYear}}-05-07&pageSize=50","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","sales","vouchers-with-items"],"query":[{"key":"fromDate","value":"{{financialYear}}-05-01"},{"key":"toDate","value":"{{financialYear}}-05-07"},{"key":"pageSize","value":"50"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"vouchers\": [],\n    \"summary\": {\n      \"total_quantity\": 0,\n      \"total_amount\": 0,\n      \"item_row_count\": 0,\n      \"voucher_count\": 0\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.sales.vouchers-with-items\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"69a49dc5d1971e43\",\n      \"tables\": [\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"VchGSTSumItemWise\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Help1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"BillingDet\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"41584756-ccc0-43a2-92c1-18384afbe08e"},{"name":"Purchase register products","id":"ad996d0f-f415-4876-9f8e-a11296c39623","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/purchases/items?fromDate={{financialYear}}-05-01&toDate={{financialYear}}-05-31&includeReturns=true","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/purchases/items</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.purchases.items</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/purchase-register-products</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { voucher_code, voucher_type_id, voucher_date, voucher_number, supplier_id, supplier_name, purchase_type_id, purchase_type_name, line_row_id, line_number, product_id, product_name, product_group_id, product_group_name, material_center_id, material_center_name, unit_id, unit_name, quantity, unit_price, line_subtotal, line_total, taxable_amount, gst_percent, gst_amount }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, fromDate, toDate (as applied), supplierId, productId, voucherId, materialCenterId, includeReturns, includeCancelled, source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>fromDate / toDate (each JavaScript-trimmed, blank = not sent) default to 1 April and 31 March and must lie inside the financial year, fromDate not after toDate (the twin's TryDate and range rule). Purchases (type 2) and, unless includeReturns is false, purchase returns (type 10); includeCancelled (default false) keeps cancelled vouchers. A purchase is positive; a purchase return is negative once (quantity, subtotal, total, taxable and GST amounts). Product lines: the Tran2 item lines (record types 2 and 7) of the vouchers whose header (Tran1, same voucher code and type) is dated in the range, kept only when the item is an item master (type 6); material_center_id is the line's MasterCode2 unless 0, else the header's; unit_id the line's CM3 unless 0, else the item's main unit; names come from Master1 (the ordinal-least name of a code). GST: the VchGSTSumItemWise rows of record type 0 or NULL grouped per voucher, voucher type, item and item line number (ItemSrNo, NULL as 0) and matched to the line with the same four keys: taxable_amount = ROUND(Σ|TaxableAmt|, 2), gst_percent = the largest |TaxRate| + |TaxRate1|, gst_amount = ROUND(Σ(|TaxAmt| + |TaxAmt1|), 2), sums ascending as the twin; several GST rows never duplicate a line; no GST row = null, never 0. line_row_id is the line's position (1, 2, …) in the year's ordered set of every item line of those voucher types (header date, voucher code, line number, item, record type, voucher type, header number) — BUSY has no row id; it does not move with filters or pages. Ordered by date, voucher code, line number, item, line_row_id. Quantities are SQLite ROUND(|Value1|, 3), amounts ROUND(|Value3|, 2) (subtotal) and ROUND(|D5|, 2) (total) — the twin's code; its contract text \"Value3 / D5\" names the two columns — and the unit price ROUND(|D2|, 2), unsigned, as the GST percentage. Dates are BUSY dates (the twin's SuppliersV1.BusyDate of the stored text) as YYYY-MM-DD. Cancellation is the shared BusyFlagsV1 rule (Tran1.Cancelled or VchCancelled is true, the number 1 or -1, or text that — white space trimmed as .NET trims it, case-insensitive — is true, yes, y or a number equal to 1 or -1, such as 1, -1, 1.0, +1); a line or row without a header is not cancelled.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>supplierId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the supplier's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>productId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the product's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>voucherId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the voucher's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>materialCenterId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the material centre</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>includeReturns</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): include return vouchers (shown negative)</td>\n<td>true</td>\n</tr>\n<tr>\n<td><code>includeCancelled</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): include cancelled vouchers</td>\n<td>false</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/purchases/items?fromDate=2025-05-01&amp;toDate=2025-05-31&amp;includeReturns=true\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","purchases","items"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-05-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"toDate","value":"{{financialYear}}-05-31"},{"description":{"content":"<p>true or false (exactly; any other text is refused): include return vouchers (shown negative)</p>\n","type":"text/plain"},"key":"includeReturns","value":"true"}],"variable":[]}},"response":[{"id":"95779491-24bd-6a75-a63d-2ecde8f912af","name":"SYNTHETIC — 200 snapshot.purchases.items (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/purchases/items?fromDate={{financialYear}}-05-01&toDate={{financialYear}}-05-31&includeReturns=true","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","purchases","items"],"query":[{"key":"fromDate","value":"{{financialYear}}-05-01"},{"key":"toDate","value":"{{financialYear}}-05-31"},{"key":"includeReturns","value":"true"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.purchases.items\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"e7d75256604200ef\",\n      \"tables\": [\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"VchGSTSumItemWise\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"ad996d0f-f415-4876-9f8e-a11296c39623"},{"name":"Pending purchase orders","id":"ecb123a2-6571-48d4-b8d6-5ba8c9bbf3a4","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/purchase-orders/pending?asOfDate={{financialYear}}-10-31&status=all","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/purchase-orders/pending</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.purchase-orders.pending</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/pending-purchase-orders</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>asOfDate</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { purchase_order_refcode, purchase_order_voucher_code, order_row_id, line_number, order_number, order_date, due_date, supplier_id, supplier_name, supplier_source, product_id, product_name, product_group_id, material_center_id, material_center_name, ordered_quantity, linked_purchase_quantity, linked_purchase_bill_count, reference_balance_quantity, pending_quantity, over_linked_quantity, status }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, fromDate, toDate (null when not sent), asOfDate, supplierId, productId, referenceNumberApplied, status, includeCancelled, source, snapshot, filters (never the reference number), pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>asOfDate is required (the twin defaults to today's UTC date kept inside the year) and must lie inside the financial year; never defaulted or clamped. fromDate / toDate (JavaScript-trimmed, blank = not sent) lie inside the year, fromDate not after toDate, and neither after asOfDate; they filter the order date only when sent, so carried-forward orders dated before the year stay by default. An order row is a Tran3 row of record type 4, method 1 and voucher type 13 — or BUSY's carried-forward form, type 1 with voucher code -1300 — with a positive RefCode, dated on or before asOfDate, its order header (type 13, if any) not cancelled unless includeCancelled. Repeated order rows (same reference, voucher, item, party and line) are kept once: the last in the twin's numbering order. The supplier is the row's MasterCode2 when not 0 (supplier_source \"reference\"), else its header's party (\"header\"). The lifecycle is every Tran3 row of the same RefCode dated on or before asOfDate, not cancelled (unless includeCancelled), in order of date, voucher, type, quantity; a row whose supplier (its MasterCode2 when not 0, else its header's party) is present and differs from the order's never counts (owner requirement beyond the reference; the twin's code — its contract text says \"another known supplier\"). reference_balance_quantity = ROUND(Σ Value1, 4) (null without rows); linked_purchase_quantity = ROUND(Σ|Value1|, 4) and linked_purchase_bill_count = distinct vouchers of its purchase adjustments (type 2, record type 4, method 2); pending_quantity = the negative balance as a positive number, over_linked_quantity = the positive balance (else 0; without rows the balance is −ordered); status open below −0.00005, over_linked above 0.00005, else closed — status (default open, case-insensitive) is open, closed, over_linked or all. No FIFO and no number matching: only the exact RefCode. referenceNumber (JavaScript-trimmed, at most 200, blank = none; never echoed or logged) matches the shown order_number or the exact reference code. order_number is Tran3.No trimmed, else the header's VchNo, else the code. order_row_id is the row's position in the year's ordered set of every order row with its header (date, reference, line, voucher, item, party, quantity, number, header number) — the reference's rowid. product_name / product_group_id from the item master (type 6); material centre the order header's. Ordered by order date, reference code, line number, order_row_id. Dates are BUSY dates (the twin's SuppliersV1.BusyDate of the stored text) as YYYY-MM-DD. Cancellation is the shared BusyFlagsV1 rule (Tran1.Cancelled or VchCancelled is true, the number 1 or -1, or text that — white space trimmed as .NET trims it, case-insensitive — is true, yes, y or a number equal to 1 or -1, such as 1, -1, 1.0, +1); a line or row without a header is not cancelled.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; filters the order date only when sent; inside the year and not after asOfDate</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; filters the order date only when sent; inside the year and not after asOfDate</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>asOfDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>yes</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year: the day the answer is calculated for. Never taken from a clock</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>supplierId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the supplier's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>productId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the product's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>referenceNumber</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>trimmed, at most 200 characters; blank = none; never echoed in the answer or logged (metadata.referenceNumberApplied says whether one was applied)</td>\n<td>none</td>\n</tr>\n<tr>\n<td><code>status</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>open, closed, over_linked or all (any case)</td>\n<td>open</td>\n</tr>\n<tr>\n<td><code>includeCancelled</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): include cancelled vouchers</td>\n<td>false</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/purchase-orders/pending?asOfDate=2025-10-31&amp;status=all\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","purchase-orders","pending"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year: the day the answer is calculated for. Never taken from a clock</p>\n","type":"text/plain"},"key":"asOfDate","value":"{{financialYear}}-10-31"},{"description":{"content":"<p>open, closed, over_linked or all (any case)</p>\n","type":"text/plain"},"key":"status","value":"all"}],"variable":[]}},"response":[{"id":"3a2a2e23-69d0-bbb1-2207-fe5e8cc79890","name":"SYNTHETIC — 200 snapshot.purchase-orders.pending (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/purchase-orders/pending?asOfDate={{financialYear}}-10-31&status=all","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","purchase-orders","pending"],"query":[{"key":"asOfDate","value":"{{financialYear}}-10-31"},{"key":"status","value":"all"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.purchase-orders.pending\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"af5ebe65bcbc981e\",\n      \"tables\": [\n        {\n          \"table\": \"Tran3\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"ecb123a2-6571-48d4-b8d6-5ba8c9bbf3a4"},{"name":"Sales-return products","id":"13688a1b-abb3-473c-9d88-6ca875fac95e","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sales-returns/items?fromDate={{financialYear}}-04-01&toDate={{financialYear}}-09-30","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/sales-returns/items</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.sales-returns.items</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/sales-return-products</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { voucher_code, voucher_date, voucher_number, customer_id, customer_name, sale_type_id, sale_type_name, line_row_id, line_number, product_id, product_name, product_group_id, product_group_name, material_center_id, material_center_name, unit_id, unit_name, return_quantity, unit_price, return_subtotal, return_total, taxable_amount, gst_percent, gst_amount }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, fromDate, toDate (as applied), customerId, productId, voucherId, includeCancelled, source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>fromDate / toDate (each JavaScript-trimmed, blank = not sent) default to 1 April and 31 March and must lie inside the financial year, fromDate not after toDate (the twin's TryDate and range rule). Sales returns (type 3); includeCancelled (default false) keeps cancelled vouchers. Every sales-return line is negative once (return_quantity, return_subtotal, return_total, taxable and GST amounts). Product lines: the Tran2 item lines (record types 2 and 7) of the vouchers whose header (Tran1, same voucher code and type) is dated in the range, kept only when the item is an item master (type 6); material_center_id is the line's MasterCode2 unless 0, else the header's; unit_id the line's CM3 unless 0, else the item's main unit; names come from Master1 (the ordinal-least name of a code). GST: the VchGSTSumItemWise rows of record type 0 or NULL grouped per voucher, voucher type, item and item line number (ItemSrNo, NULL as 0) and matched to the line with the same four keys: taxable_amount = ROUND(Σ|TaxableAmt|, 2), gst_percent = the largest |TaxRate| + |TaxRate1|, gst_amount = ROUND(Σ(|TaxAmt| + |TaxAmt1|), 2), sums ascending as the twin; several GST rows never duplicate a line; no GST row = null, never 0. line_row_id is the line's position (1, 2, …) in the year's ordered set of every item line of those voucher types (header date, voucher code, line number, item, record type, voucher type, header number) — BUSY has no row id; it does not move with filters or pages. Ordered by date, voucher code, line number, item, line_row_id. Quantities are SQLite ROUND(|Value1|, 3), amounts ROUND(|Value3|, 2) (subtotal) and ROUND(|D5|, 2) (total) — the twin's code; its contract text \"Value3 / D5\" names the two columns — and the unit price ROUND(|D2|, 2), unsigned, as the GST percentage. Dates are BUSY dates (the twin's SuppliersV1.BusyDate of the stored text) as YYYY-MM-DD. Cancellation is the shared BusyFlagsV1 rule (Tran1.Cancelled or VchCancelled is true, the number 1 or -1, or text that — white space trimmed as .NET trims it, case-insensitive — is true, yes, y or a number equal to 1 or -1, such as 1, -1, 1.0, +1); a line or row without a header is not cancelled.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>customerId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the customer's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>productId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the product's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>voucherId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647: the voucher's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>includeCancelled</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): include cancelled vouchers</td>\n<td>false</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/sales-returns/items?fromDate=2025-04-01&amp;toDate=2025-09-30\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","sales-returns","items"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-04-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"toDate","value":"{{financialYear}}-09-30"}],"variable":[]}},"response":[{"id":"0a2d2dd5-d6b8-f04a-a72b-f2b85d22baec","name":"SYNTHETIC — 200 snapshot.sales-returns.items (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/sales-returns/items?fromDate={{financialYear}}-04-01&toDate={{financialYear}}-09-30","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","sales-returns","items"],"query":[{"key":"fromDate","value":"{{financialYear}}-04-01"},{"key":"toDate","value":"{{financialYear}}-09-30"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.sales-returns.items\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"e7d75256604200ef\",\n      \"tables\": [\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"VchGSTSumItemWise\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"13688a1b-abb3-473c-9d88-6ca875fac95e"},{"name":"Customer sales register","id":"e2ced4da-0a30-4412-9127-2bc2739ec40a","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/{{customerId}}/sales-register?fromDate={{financialYear}}-04-01&toDate={{financialYear}}-09-30","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/customers/{customerId}/sales-register</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.customers.sales-register</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/customer-sales-register</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>path: customerId</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ rows: array of { voucher_code, voucher_type_id, transaction_type, voucher_date, voucher_number, customer_id, customer_name, sale_type_id, sale_type_name, material_center_id, material_center_name, total_amount, sale_amount, taxable_amount, gst_amount }, summary: { voucher_count, sales_total, returns_total, net_total, net_gst_amount } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, customerId, fromDate, toDate (as applied), includeReturns, includeCancelled, source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>fromDate / toDate (each JavaScript-trimmed, blank = not sent) default to 1 April and 31 March and must lie inside the financial year, fromDate not after toDate (the twin's TryDate and range rule). The customer's Tran1 vouchers of type 9 (sales) and, unless includeReturns is false, 3 (returns) with a voucher code, dated in the range; includeCancelled (default false) keeps cancelled vouchers. transaction_type sale / sales_return; total_amount = ROUND(|VchAmtBaseCur|, 2) and sale_amount = ROUND(|VchSalePurcAmt|, 2), returns negative once; taxable_amount / gst_amount from the voucher's item-wise GST rows (record type 0 or NULL; ROUND(Σ|TaxableAmt|, 2), ROUND(Σ(|TaxAmt| + |TaxAmt1|), 2), ascending) with the voucher's sign, null without any. summary (over the whole range, never per page): voucher_count, sales_total, returns_total, net_total, net_gst_amount — ROUND(…, 2) of the rows' rounded values summed in row order (null GST ignored). An unknown customer answers no rows and a zero summary, as the twin. Ordered by date, voucher code, voucher type, number. Dates are BUSY dates (the twin's SuppliersV1.BusyDate of the stored text) as YYYY-MM-DD. Cancellation is the shared BusyFlagsV1 rule (Tran1.Cancelled or VchCancelled is true, the number 1 or -1, or text that — white space trimmed as .NET trims it, case-insensitive — is true, yes, y or a number equal to 1 or -1, such as 1, -1, 1.0, +1); a line or row without a header is not cancelled.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>customerId</code></td>\n<td>path</td>\n<td>integer</td>\n<td>yes</td>\n<td>whole number from 1 to 2147483647: the customer's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>includeReturns</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): include return vouchers (shown negative)</td>\n<td>true</td>\n</tr>\n<tr>\n<td><code>includeCancelled</code></td>\n<td>query</td>\n<td>boolean</td>\n<td>no</td>\n<td>true or false (exactly; any other text is refused): include cancelled vouchers</td>\n<td>false</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/customers/1001/sales-register?fromDate=2025-04-01&amp;toDate=2025-09-30\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","{{customerId}}","sales-register"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-04-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"toDate","value":"{{financialYear}}-09-30"}],"variable":[]}},"response":[{"id":"02c16066-0002-c838-6bbb-82b03fddc283","name":"SYNTHETIC — 200 snapshot.customers.sales-register (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/{{customerId}}/sales-register?fromDate={{financialYear}}-04-01&toDate={{financialYear}}-09-30","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","{{customerId}}","sales-register"],"query":[{"key":"fromDate","value":"{{financialYear}}-04-01"},{"key":"toDate","value":"{{financialYear}}-09-30"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"rows\": [],\n    \"summary\": {\n      \"voucher_count\": 0,\n      \"sales_total\": 0,\n      \"returns_total\": 0,\n      \"net_total\": 0,\n      \"net_gst_amount\": \"Synthetic net_gst_amount\"\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.customers.sales-register\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"92467c780d6bc640\",\n      \"tables\": [\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"VchGSTSumItemWise\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"e2ced4da-0a30-4412-9127-2bc2739ec40a"}],"id":"7316c8fb-ad65-4ba9-8172-cc4f65340397","description":"<p>Snapshot reads of the reports in the live family <em>Registers, orders and invoices</em> (17); each request names its live equivalent.</p>\n<ul>\n<li><strong>Sales register</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/registers/sales</code></li>\n<li><strong>Purchase register</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/registers/purchase</code></li>\n<li><strong>Sales return / credit note register</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/registers/sales-return</code></li>\n<li><strong>Purchase return / debit note register</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/registers/purchase-return</code></li>\n<li><strong>Payment register</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/registers/payment</code></li>\n<li><strong>Receipt register</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/registers/receipt</code></li>\n<li><strong>Journal register</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/registers/journal</code></li>\n<li><strong>Contra register</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/registers/contra</code></li>\n<li><strong>Pending sales orders</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/sales-orders/pending</code></li>\n<li><strong>Pending sales-order vouchers</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/sales-orders/pending-vouchers</code></li>\n<li><strong>Sale invoices</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/sales/invoices</code></li>\n<li><strong>Sale invoice items</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/sales/invoices/{voucherId}/items</code></li>\n<li><strong>Sale vouchers with items</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/sales/vouchers-with-items</code></li>\n<li><strong>Purchase register products</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/purchases/items</code></li>\n<li><strong>Pending purchase orders</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/purchase-orders/pending</code></li>\n<li><strong>Sales-return products</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/sales-returns/items</code></li>\n<li><strong>Customer sales register</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/customers/{customerId}/sales-register</code></li>\n</ul>\n","_postman_id":"7316c8fb-ad65-4ba9-8172-cc4f65340397","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Dashboards and credit-line stream","item":[{"name":"Dashboard sales summary","id":"c12a38a6-344c-45fe-bb75-4af16f96c1a8","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/dashboard/sales-summary","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/dashboard/sales-summary</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.dashboard.sales-summary</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/dashboard-sales-summary</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>nothing beyond the path</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>not paged</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ daily: array of { date, invoiceCount, totalSalesAmount }, weekly: array of { weekNumber, weekLabel, startDate, endDate, invoiceCount, totalSalesAmount }, monthly: array of { monthNumber, monthLabel, startDate, endDate, invoiceCount, totalSalesAmount }, quarterly: array of { quarterNumber, quarterLabel, … }, halfYearly: array of { halfYearNumber, halfYearLabel, … } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, startDate, endDate, source, snapshot, filters, rowCount, dailyRowCount, weeklyRowCount, monthlyRowCount, quarterlyRowCount, halfYearlyRowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>The whole financial year, 1 April to 31 March (366 days when 29 February falls in it). Sales are Tran1 vouchers of type 9 with VchSalePurcAmt, else VchAmtBaseCur, else 0; sales returns (type 3) subtract the absolute amount; invoiceCount = distinct sale vouchers of the day; amounts exact (decimal), each day rounded to two places half away from zero. daily: every date of the year, zero-filled; weekly: seven-day blocks from 1 April (W1 … W53, the last 1 or 2 days), not calendar weeks; monthly April → March (monthLabel \"Apr 2025\" …); quarterly Q1–Q4; halfYearly H1–H2 — each the rounded sum of its days. <strong>Cancelled vouchers (Cancelled or VchCancelled set: true, 1, -1, yes, y) are left out of every total and count</strong> (the twin's owner-directed correction; the reference did not filter). Not paged (a bounded answer).</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/dashboard/sales-summary\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","dashboard","sales-summary"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"ec54379f-7a5e-141d-cfb4-75e20e738bee","name":"SYNTHETIC — 200 snapshot.dashboard.sales-summary (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/dashboard/sales-summary"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"daily\": [],\n    \"weekly\": [],\n    \"monthly\": [],\n    \"quarterly\": [],\n    \"halfYearly\": []\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.dashboard.sales-summary\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"331e0982eaf7a6c4\",\n      \"tables\": [\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"c12a38a6-344c-45fe-bb75-4af16f96c1a8"},{"name":"Dashboard sales trend","id":"630a02d0-5547-46fe-8bc6-56cf11d36a48","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/dashboard/sales-trend?asOnDate={{financialYear}}-10-31&period=monthly","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/dashboard/sales-trend</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.dashboard.sales-trend</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/dashboard-sales-trend</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>asOnDate</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>not paged</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ period, startDate, endDate, total_sales_amount, total_sales_return_amount, total_receipt_amount }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, period, startDate, endDate, financialYearStartDate, financialYearEndDate, coverage (full / partial), coveredStartDate, coveredEndDate, calculationDate (= asOnDate), timeZone (Asia/Kolkata), source, snapshot, filters, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 PERIOD_OUTSIDE_FINANCIAL_YEAR (field period: the period lies entirely outside the selected year); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>asOnDate is required (the twin uses the PC's India calendar day; a snapshot has no single \"today\"): a real YYYY-MM-DD India calendar day (Asia/Kolkata), not bounded to the year. period: daily (default), weekly, monthly or yearly, exactly. The period from asOnDate: daily = that day; weekly = its Monday to Sunday; monthly = its calendar month; yearly = the selected financial year. The selected year's data answers only the days of the period inside that year — never another year's: coverage is full or partial (totals over coveredStartDate … coveredEndDate); a period entirely outside the year is 422 PERIOD_OUTSIDE_FINANCIAL_YEAR (field period) after the company, year and published-data checks and before any read; data.startDate / endDate are the period itself. Totals (exact, two places): total_sales_amount = Σ |sale amount| (VchSalePurcAmt, else VchAmtBaseCur), total_sales_return_amount = Σ |return amount|, total_receipt_amount = one amount per receipt voucher (Tran2 type 14, record type 1, in the period): its largest |CashFlow ?? Value1 ?? 0| (CashFlow 0 is kept). Cancelled vouchers are left out of every total (the twin's owner-directed correction), the receipt's header joined on the voucher code alone as the twin.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>period</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>daily, weekly, monthly or yearly (exact case)</td>\n<td>daily</td>\n</tr>\n<tr>\n<td><code>asOnDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>see Required</td>\n<td>a real calendar date written YYYY-MM-DD: the India calendar day (Asia/Kolkata) the period is taken from; any real date (a period wholly outside the year is 422 PERIOD_OUTSIDE_FINANCIAL_YEAR)</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/dashboard/sales-trend?asOnDate=2025-10-31&amp;period=monthly\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","dashboard","sales-trend"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD: the India calendar day (Asia/Kolkata) the period is taken from; any real date (a period wholly outside the year is 422 PERIOD_OUTSIDE_FINANCIAL_YEAR)</p>\n","type":"text/plain"},"key":"asOnDate","value":"{{financialYear}}-10-31"},{"description":{"content":"<p>daily, weekly, monthly or yearly (exact case)</p>\n","type":"text/plain"},"key":"period","value":"monthly"}],"variable":[]}},"response":[{"id":"09f0faef-672b-0e4e-36be-1a14722c19df","name":"SYNTHETIC — 200 snapshot.dashboard.sales-trend (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/dashboard/sales-trend?asOnDate={{financialYear}}-10-31&period=monthly","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","dashboard","sales-trend"],"query":[{"key":"asOnDate","value":"{{financialYear}}-10-31"},{"key":"period","value":"monthly"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"period\": \"monthly\",\n    \"startDate\": \"2026-04-01\",\n    \"endDate\": \"2026-10-31\",\n    \"total_sales_amount\": 0,\n    \"total_sales_return_amount\": 0,\n    \"total_receipt_amount\": 0\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.dashboard.sales-trend\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"b2f210a5d9e0c95d\",\n      \"tables\": [\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"630a02d0-5547-46fe-8bc6-56cf11d36a48"}],"id":"38e966b3-59c1-46e7-b24f-7045f37acd3a","description":"<p>Snapshot reads of the reports in the live family <em>Dashboards and credit-line stream</em> (2); each request names its live equivalent.</p>\n<ul>\n<li><strong>Dashboard sales summary</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/dashboard/sales-summary</code></li>\n<li><strong>Dashboard sales trend</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/dashboard/sales-trend</code></li>\n</ul>\n","_postman_id":"38e966b3-59c1-46e7-b24f-7045f37acd3a","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Inventory and ageing","item":[{"name":"Receivables ageing","id":"69c90de7-0255-4f27-9cf4-681d74160bed","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/receivables/ageing?customerId={{customerId}}&fromDate={{financialYear}}-04-01&toDate={{financialYear}}-10-31","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/receivables/ageing</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.receivables.ageing</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/ageing-analysis-receivables</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>fromDate, toDate; exactly one of customerId and accountName</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { reference_number, transaction_type, transaction_date, transaction_date_raw, due_date, due_date_raw, total_amount, pending_amount, age_0_30_days, age_31_60_days, age_61_90_days, age_91_120_days, age_121_150_days, age_151_plus_days, age_days, ref_code, voucher_code, voucher_type, voucher_series_code, signed_balance }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, fromDate, toDate, statusDate, source, snapshot, filters (never accountName), pagination, customerId, selectedBy, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 NOT_FOUND (field customerId or accountName); 422 BUSY_DATA_INCONSISTENT (the customer code is repeated; several customers share the accountName; a voucher header or bill reference is repeated); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>Member names follow this surface: fromDate/toDate are the twin's startDate/endDate. Exactly one of customerId or accountName (exact name or alias, case and spaces counting); fromDate and toDate are required, statusDate defaults to toDate, all inside the financial year. As the twin: the customer's new bill references (Tran3 record type 1, method 1, MasterCode2 0, dated in the range, approval status present and not 2), each balanced over every row of its RefCode dated on or before statusDate whose TranType is not 1; a bill is pending when ROUND(balance, 2) &lt; 0 (exact decimal sums), aged from its due date (else its bill date) to statusDate, in at most one bucket (a bill not yet due in none, the bucket members are null). Rows of cancelled vouchers (Tran1.Cancelled/VchCancelled) are left out, as the twin. Paged (the twin is unpaged) in the twin's order: bill date, voucher type, reference number (binary), reference, voucher, line — not by age. accountName is never echoed or logged.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>customerId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>see Required</td>\n<td>whole number from 1 to 2147483647: the customer's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>accountName</code></td>\n<td>query</td>\n<td>string</td>\n<td>see Required</td>\n<td>the account's name, trimmed, not blank, at most 255 characters; never echoed in the answer or logged</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>yes</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>yes</td>\n<td>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>statusDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>no</td>\n<td>a real calendar date written YYYY-MM-DD, inside the financial year</td>\n<td>toDate</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/receivables/ageing?customerId=1001&amp;fromDate=2025-04-01&amp;toDate=2025-10-31\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","receivables","ageing"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>whole number from 1 to 2147483647: the customer's code</p>\n","type":"text/plain"},"key":"customerId","value":"{{customerId}}"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-04-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; whether it must lie inside the financial year, and what a missing value means, is in the operation's rules</p>\n","type":"text/plain"},"key":"toDate","value":"{{financialYear}}-10-31"}],"variable":[]}},"response":[{"id":"494b548c-3b8f-ac6f-9611-b744e5bc9dc9","name":"SYNTHETIC — 200 snapshot.receivables.ageing (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/receivables/ageing?customerId={{customerId}}&fromDate={{financialYear}}-04-01&toDate={{financialYear}}-10-31","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","receivables","ageing"],"query":[{"key":"customerId","value":"{{customerId}}"},{"key":"fromDate","value":"{{financialYear}}-04-01"},{"key":"toDate","value":"{{financialYear}}-10-31"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"value":"application/json; charset=utf-8","key":"Content-Type"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.receivables.ageing\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"af5ebe65bcbc981e\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran3\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"69c90de7-0255-4f27-9cf4-681d74160bed"},{"name":"Inventory daybooks","id":"45df99e4-8af5-42ce-834f-737f0a4ec32a","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/inventory/daybooks?fromDate={{financialYear}}-05-01&toDate={{financialYear}}-05-31","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/inventory/daybooks</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.inventory.daybooks</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/inventory-daybooks</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>fromDate, toDate</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { date, voucher_type, voucher_number, particular, item, quantity, unit }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, fromDate, toDate, source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (an item line's voucher has several headers; a row's party, item or unit code is held by several masters); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>fromDate and toDate are required (real YYYY-MM-DD inside the financial year, JavaScript-trimmed, fromDate not after toDate; the twin's rules and messages). The item lines (Tran2 record type 2, an item code above 0, a non-zero quantity) of the reference's seven voucher types — 2 Purchase Voucher, 3 Sale Return, 4 Material Receipt, 5 Stock Transfer, 9 Sales Invoice, 10 Purchase Return, 11 Material Issue — whose Tran1 header (same code and type) is dated (SQLite DATE()) in the range. Grouped by date, voucher and item; quantity = ROUND(|Σ Value1|, 3) of the exact decimal sum (a transfer whose out and in lines cancel shows 0). date dd-mm-yyyy; voucher_number the header's number trimmed, else the voucher code; particular the party's print name trimmed, else its name, else empty; item the item master's (type 6) print name trimmed, else its name, else the item code; unit the name of the item's unit master (CM1), else empty. Ordered by date, the voucher types in that order, voucher code, item (binary), item code — paged (the twin is unpaged); pagination.totalRows counts every row. An item line of any date whose voucher has several headers, or a row whose party, item or unit is held by several masters, refuses the answer (the twin). Cancelled vouchers are left out (the shared BusyFlagsV1 rule over Tran1.Cancelled / VchCancelled: true, the number 1 or -1, or text that — white space trimmed as .NET trims it, case-insensitive — is true, yes, y or a number equal to ±1); a row without a voucher header (an opening balance) is kept — a correction of the reference, as the twin.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>fromDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>yes</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>toDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>yes</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/inventory/daybooks?fromDate=2025-05-01&amp;toDate=2025-05-31\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","inventory","daybooks"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year</p>\n","type":"text/plain"},"key":"fromDate","value":"{{financialYear}}-05-01"},{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year</p>\n","type":"text/plain"},"key":"toDate","value":"{{financialYear}}-05-31"}],"variable":[]}},"response":[{"id":"7e3b1953-ce71-c5c2-c50c-bf7c0da87f3f","name":"SYNTHETIC — 200 snapshot.inventory.daybooks (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/inventory/daybooks?fromDate={{financialYear}}-05-01&toDate={{financialYear}}-05-31","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","inventory","daybooks"],"query":[{"key":"fromDate","value":"{{financialYear}}-05-01"},{"key":"toDate","value":"{{financialYear}}-05-31"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.inventory.daybooks\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"c471a00a303eb9b2\",\n      \"tables\": [\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"45df99e4-8af5-42ce-834f-737f0a4ec32a"},{"name":"Stock ageing (serial numbers)","id":"fe5eea4d-4d9d-46cf-8cd1-776284cdd2a8","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/inventory/stock-aging?asOnDate={{financialYear}}-10-31&productId={{productId}}","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/inventory/stock-aging</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.inventory.stock-aging</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/stock-aging-receivable-issuable</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>asOnDate; at least one of productId and materialCenterId (both may be sent)</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ rows: array of { product_id, product_name, product_group_id, product_group_name, material_center_id, material_center_name, manufacturing_brand, consumer_brand, product_location, product_price, product_self_value, global_oldest_serial_no, global_oldest_date, global_oldest_age_days, center_oldest_serial_no, center_oldest_date, center_oldest_age_days, fifo_aging_date, total_quantity, average_age_days, latest_transaction_date, mc_id, mc_name, price, average_age, newest_date }, summary: { total_product_material_center_combinations, total_item_material_center_combinations, total_unique_products, total_unique_material_centers, total_serial_numbers, oldest_stock_age_overall_days, oldest_stock_age_overall, average_stock_age_days, average_stock_age } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, asOnDate, asOnDateSource (\"request\"), timeZone, productId, materialCenterId, source, snapshot, filters, pagination (over data.rows), rowCount, transactionCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 400 INVALID_PARAMETER (field productId: neither productId nor materialCenterId sent); 404 NOT_FOUND (field productId or materialCenterId: not a product, type 6, or a material centre, type 11); 422 BUSY_DATA_INCONSISTENT (a row's product, centre, group or named master is held by several masters; a product has several differing optional-field rows); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>asOnDate is required (real YYYY-MM-DD inside the financial year, JavaScript-trimmed; the twin defaults to today in India); never defaulted or clamped. productId or materialCenterId is required — at least one, both allowed (unlike the twin, which requires neither: ItemSerialNo has only two indexes, so the read is always bounded to one product or centre). Only movements dated (SQLite DATE()) on or before asOnDate are read — for which serials are in stock, their centre, earliest positive and latest dates, count, age and the summary (the twin's correction of the reference). Movements of the nine voucher types (1, 2, 3, 4, 5, 8, 9, 10, 11); a serial is its text trimmed of spaces (blank serials left out), with a positive product and centre code; a serial, product and centre combination is in stock when its exact net quantity is above zero (a serial moved between centres is in stock only where its net is positive). Its age = asOnDate − its earliest positive movement, never negative. Rows per product and centre: total_quantity (serials), average_age_days, the centre's oldest serial and the product's oldest across centres (ties by serial, binary), latest_transaction_date, the product's name (trimmed, else its code), group, price (D3) and self value (D9), the centre's name (trimmed, else its code), and the masters named by the product's optional fields OF4 (manufacturing_brand), OF5 (consumer_brand) and OF7 (product_location) — a master whose code is exactly that trimmed text. The reference's aliases mc_id, mc_name, price, average_age, newest_date are kept (the twin). Two decimals as the reference's roundToTwo. Ordered by product, the centre's oldest age (descending), centre — paged (the twin is unpaged); data.summary covers every row, never one page (the weighted average over the rows' rounded averages, as the reference); metadata.transactionCount = the movements of the serials in stock. A known product or centre without stock answers no rows and a zero summary. Tran1 is read for the cancellation rule. Cancelled vouchers are left out (the shared BusyFlagsV1 rule over Tran1.Cancelled / VchCancelled: true, the number 1 or -1, or text that — white space trimmed as .NET trims it, case-insensitive — is true, yes, y or a number equal to ±1); a row without a voucher header (an opening balance) is kept — a correction of the reference, as the twin.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>asOnDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>yes</td>\n<td>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year: only serial movements on or before it count. Never taken from a clock</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>productId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>see Required</td>\n<td>whole number from 1 to 2147483647: the product's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>materialCenterId</code></td>\n<td>query</td>\n<td>integer</td>\n<td>see Required</td>\n<td>whole number from 1 to 2147483647: the material centre</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/inventory/stock-aging?asOnDate=2026-03-31&amp;productId=2001\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","inventory","stock-aging"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD; surrounding spaces are removed and a blank value counts as not sent; inside the financial year: only serial movements on or before it count. Never taken from a clock</p>\n","type":"text/plain"},"key":"asOnDate","value":"{{financialYear}}-10-31"},{"description":{"content":"<p>whole number from 1 to 2147483647: the product's code</p>\n","type":"text/plain"},"key":"productId","value":"{{productId}}"}],"variable":[]}},"response":[{"id":"c34d0515-aafd-11b8-1479-5a30b7ead3a9","name":"SYNTHETIC — 200 snapshot.inventory.stock-aging (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/inventory/stock-aging?asOnDate={{financialYear}}-10-31&productId={{productId}}","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","inventory","stock-aging"],"query":[{"key":"asOnDate","value":"{{financialYear}}-10-31"},{"key":"productId","value":"{{productId}}"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"rows\": [],\n    \"summary\": {\n      \"total_product_material_center_combinations\": 0,\n      \"total_item_material_center_combinations\": 0,\n      \"total_unique_products\": 0,\n      \"total_unique_material_centers\": 0,\n      \"total_serial_numbers\": \"Synthetic total_serial_numbers\",\n      \"oldest_stock_age_overall_days\": 0,\n      \"oldest_stock_age_overall\": 0,\n      \"average_stock_age_days\": 0,\n      \"average_stock_age\": 0\n    }\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.inventory.stock-aging\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"bcae7c35d4b2985a\",\n      \"tables\": [\n        {\n          \"table\": \"ItemSerialNo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"fe5eea4d-4d9d-46cf-8cd1-776284cdd2a8"}],"id":"b2edc9fb-20c7-4341-ba27-24797884df78","description":"<p>Snapshot reads of the reports in the live family <em>Inventory and ageing</em> (3); each request names its live equivalent.</p>\n<ul>\n<li><strong>Receivables ageing</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/receivables/ageing</code></li>\n<li><strong>Inventory daybooks</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/inventory/daybooks</code></li>\n<li><strong>Stock ageing (serial numbers)</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/inventory/stock-aging</code></li>\n</ul>\n","_postman_id":"b2edc9fb-20c7-4341-ba27-24797884df78","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Unbilled customers and profile","item":[{"name":"Unbilled customers","id":"37d5bad7-02d5-439d-9c3b-b5c69935282a","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/unbilled?asOnDate={{financialYear}}-10-31&billingMode=positive&billingRule=lastBill&billingWindow=30_days","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/customers/unbilled</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.customers.unbilled</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/unbilled-customers</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>asOnDate</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>array of { customer_id, customer_name, parent_group_id, parent_group_name, root_group_id, root_group_name, mobile_number, last_bill_1…3_{date,days,amount}, first_bill_1…2_{date,days,amount}, last_receipt_1…3_{date,days,amount}, first_receipt_1…2_{date,days,amount}, closing_balance, closing_balance_type, closing_balance_display, closing_signed }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, asOnDate, financialYearStart, billingMode, billingRule, billingWindow, customDays, windowStartDate, windowEndDate, source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 422 BUSY_DATA_INCONSISTENT (a listed customer has several master, group or differing mobile rows); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>asOnDate is required (the twin defaults to the India calendar day). billingMode (positive/negative), billingRule (lastBill/anyBill) and billingWindow (7_days/30_days/quarter/6_months/custom) come together or not at all; customDays (1–2147483647, the twin's bound) only and always with custom. The window ends on asOnDate and starts 7, 30 or customDays days before it, or 3 or 6 calendar months before it (a missing day becoming the month's last day). As the twin: Sundry Debtors are type-2 customers whose group, or that group's group, is code 116 or named exactly \"Sundry Debtors\" after trimming spaces (a documented constant); closing = ROUND2(ROUND2(Σ Folio1.D1 of type 2) + ROUND2(record-type 1 lines from 1 April to asOnDate)); bill history = sales (9), receipts = type 14, record types 1 and 17, one posting per voucher; lines of cancelled vouchers and opening entries (type 1) are left out; amounts are exact decimals shown as two-decimal text. Without a filter: customers with no bill on asOnDate. Tran1 is read for the cancellation rule. Paged (the twin is unpaged); ordered by name (binary), then code.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n<tr>\n<td><code>asOnDate</code></td>\n<td>query</td>\n<td>date</td>\n<td>yes</td>\n<td>a real calendar date written YYYY-MM-DD, inside the financial year (1 April to 31 March): the day the answer is calculated for. Never taken from a clock</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>billingMode</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>positive or negative (exact case); send together with billingRule and billingWindow</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>billingRule</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>lastBill or anyBill (exact case); required when billingMode is sent</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>billingWindow</code></td>\n<td>query</td>\n<td>string</td>\n<td>no</td>\n<td>7_days, 30_days, quarter, 6_months or custom (exact case); required when billingMode is sent</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>customDays</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>whole number from 1 to 2147483647; only with billingWindow=custom, and then required</td>\n<td>—</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/customers/unbilled?asOnDate=2025-10-31&amp;billingMode=positive&amp;billingRule=lastBill&amp;billingWindow=30_days\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","unbilled"],"host":["{{cloudBaseUrl}}"],"query":[{"description":{"content":"<p>a real calendar date written YYYY-MM-DD, inside the financial year (1 April to 31 March): the day the answer is calculated for. Never taken from a clock</p>\n","type":"text/plain"},"key":"asOnDate","value":"{{financialYear}}-10-31"},{"description":{"content":"<p>positive or negative (exact case); send together with billingRule and billingWindow</p>\n","type":"text/plain"},"key":"billingMode","value":"positive"},{"description":{"content":"<p>lastBill or anyBill (exact case); required when billingMode is sent</p>\n","type":"text/plain"},"key":"billingRule","value":"lastBill"},{"description":{"content":"<p>7_days, 30_days, quarter, 6_months or custom (exact case); required when billingMode is sent</p>\n","type":"text/plain"},"key":"billingWindow","value":"30_days"}],"variable":[]}},"response":[{"id":"86f862e6-9f49-cb17-5204-5029cb2c4d6f","name":"SYNTHETIC — 200 snapshot.customers.unbilled (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":{"raw":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/unbilled?asOnDate={{financialYear}}-10-31&billingMode=positive&billingRule=lastBill&billingWindow=30_days","host":["{{cloudBaseUrl}}"],"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","unbilled"],"query":[{"key":"asOnDate","value":"{{financialYear}}-10-31"},{"key":"billingMode","value":"positive"},{"key":"billingRule","value":"lastBill"},{"key":"billingWindow","value":"30_days"}]}},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": [],\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.customers.unbilled\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"70fda1b7968cf821\",\n      \"tables\": [\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Folio1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran2\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Tran1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"MasterAddressInfo\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"37d5bad7-02d5-439d-9c3b-b5c69935282a"}],"id":"c8573b03-959b-4702-ac94-04d799818d60","description":"<p>Snapshot reads of the reports in the live family <em>Unbilled customers and profile</em> (1); each request names its live equivalent.</p>\n<ul>\n<li><strong>Unbilled customers</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/customers/unbilled</code></li>\n</ul>\n","_postman_id":"c8573b03-959b-4702-ac94-04d799818d60","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}},{"name":"Customer discounts","item":[{"name":"Customer product-group discounts","id":"177c88b4-7a6c-4d32-b05e-5ac5b18ffb39","request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{cloudApiToken}}"}]},"isInherited":false},"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/{{customerId}}/product-group-discounts","description":"<p><strong>Snapshot read</strong> — answers from the latest available snapshot; the PC is not contacted. Available only where AI Zeny has enabled snapshot routes (elsewhere <code>404 NOT_FOUND</code>).</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Route</td>\n<td><code>GET https://api.aizeny.com/v1/snapshot/{companyCode}/{financialYear}/customers/{customerId}/product-group-discounts</code></td>\n</tr>\n<tr>\n<td>Source</td>\n<td>Snapshot: the PC may be offline</td>\n</tr>\n<tr>\n<td>Operation</td>\n<td><code>snapshot.customers.product-group-discounts</code></td>\n</tr>\n<tr>\n<td>Live equivalent</td>\n<td><code>POST /v1/customer-product-group-discounts</code> — the same report read from the PC; calculations follow it, while member names, paging, required members and some shapes may differ (see Rules)</td>\n</tr>\n<tr>\n<td>Required</td>\n<td>path: customerId</td>\n</tr>\n<tr>\n<td>Paging</td>\n<td>page ≥ 1 (default 1), pageSize 1–500 (default 100); metadata.pagination { page, pageSize, returned, totalRows, hasMore, nextPage }</td>\n</tr>\n<tr>\n<td><code>data</code></td>\n<td>{ rows: array of { discount_row_id, customer_id, customer_name, customer_alias, product_group_id, product_group_name, product_group_alias, effective_date, mrp, sale_price, sale_price_du, discount_percent, compound_discount_percent, d6_raw, d8_raw, d9_raw, c1_raw, c2_raw } }</td>\n</tr>\n<tr>\n<td><code>metadata</code></td>\n<td>apiVersion, operation, requestId, companyCode, financialYear, customerId, selectedBy, source, snapshot, filters, pagination, rowCount, elapsedMs, executedAt</td>\n</tr>\n<tr>\n<td>Errors</td>\n<td>400 INVALID_PARAMETER (field); 401 TOKEN_INVALID / TOKEN_EXPIRED; 403 ORGANIZATION_ACCESS_DISABLED / SUBSCRIPTION_* / FEATURE_NOT_ENTITLED (API access); 414 URI_TOO_LONG; 429 RATE_LIMITED; 503 SNAPSHOT_UNREADABLE (retryable); 403 COMPANY_NOT_ALLOWED; 404 SNAPSHOT_NOT_FOUND { companyCode, financialYear }; 409 SNAPSHOT_SET_CHANGED / SNAPSHOT_SKEW_EXCEEDED (retryable) / SNAPSHOT_FRESHNESS_UNKNOWN (only with setId or maxSkewMs); 429 SNAPSHOT_BUSY (retryable); 504 SNAPSHOT_QUERY_TIMEOUT (retryable); 404 NOT_FOUND (field customerId: not a customer); 422 BUSY_DATA_INCONSISTENT (the customer code, or a product group code, held by more than one master record); 404 SNAPSHOT_TABLE_MISSING { table }; 422 SNAPSHOT_SCHEMA_UNSUPPORTED { table, missing }; 422 RESULT_TOO_LARGE</td>\n</tr>\n<tr>\n<td>Rules</td>\n<td>The customer by its code (the twin's customerName selector is the customers list's search on this surface). Every sale discount row of the customer (Tran10 voucher type 9, record type 3, no third master: MasterCode3 0 or NULL) — no current-discount rule is invented. Each with its product group (MasterCode2; the group's Master1 row of type 5 gives product_group_name / _alias, trimmed, \"\" when the group is missing — the row is kept), effective_date (YYYY-MM-DD, the BUSY date), the reference's value names discount_percent (D1), mrp (D2), sale_price (D3), sale_price_du (D4), compound_discount_percent (D5), d6_raw, d8_raw, d9_raw (rounded to four places; a missing value is 0), c1_raw, c2_raw (trimmed). discount_row_id is the row's position (1, 2, …) in the customer's complete list ordered by group name (binary), group code, date, BUSY's SrNo, then every value — it numbers the whole list, never the page.</td>\n</tr>\n</tbody>\n</table>\n</div><div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>In</th>\n<th>Type</th>\n<th>Required</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>customerId</code></td>\n<td>path</td>\n<td>integer</td>\n<td>yes</td>\n<td>whole number from 1 to 2147483647: the customer's code</td>\n<td>—</td>\n</tr>\n<tr>\n<td><code>page</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>page number, a whole number from 1</td>\n<td>1</td>\n</tr>\n<tr>\n<td><code>pageSize</code></td>\n<td>query</td>\n<td>integer</td>\n<td>no</td>\n<td>rows per page, a whole number from 1 to 500</td>\n<td>100</td>\n</tr>\n</tbody>\n</table>\n</div><p>Also accepts <code>maxSkewMs</code>, <code>setId</code> and <code>source</code> (see the folder description). Example request:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-http\">GET /v1/snapshot/COMP0001/2025/customers/1001/product-group-discounts\nAuthorization: Bearer &lt;organization API token&gt;\n</code></pre>\n","urlObject":{"path":["v1","snapshot","{{companyCode}}","{{financialYear}}","customers","{{customerId}}","product-group-discounts"],"host":["{{cloudBaseUrl}}"],"query":[],"variable":[]}},"response":[{"id":"a8026058-c583-2393-41ea-61fc4601b794","name":"SYNTHETIC — 200 snapshot.customers.product-group-discounts (source shape, not live evidence)","originalRequest":{"method":"GET","header":[],"url":"{{cloudBaseUrl}}/v1/snapshot/{{companyCode}}/{{financialYear}}/customers/{{customerId}}/product-group-discounts"},"status":"OK","code":200,"_postman_previewlanguage":"json","header":[{"key":"Content-Type","value":"application/json; charset=utf-8"}],"cookie":[],"responseTime":"1","body":"{\n  \"success\": true,\n  \"data\": {\n    \"rows\": []\n  },\n  \"metadata\": {\n    \"apiVersion\": \"v1\",\n    \"operation\": \"snapshot.customers.product-group-discounts\",\n    \"requestId\": \"synthetic-request-id\",\n    \"source\": \"snapshot\",\n    \"companyCode\": \"COMP0001\",\n    \"financialYear\": \"2026\",\n    \"snapshot\": {\n      \"setId\": \"c82dc218fa19aed0\",\n      \"tables\": [\n        {\n          \"table\": \"Tran10\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        },\n        {\n          \"table\": \"Master1\",\n          \"version\": \"synthetic-v1\",\n          \"snapshotAt\": \"2026-05-10T10:00:00.000Z\",\n          \"publishedAt\": \"2026-05-10T10:00:00.000Z\"\n        }\n      ],\n      \"readTimesKnown\": true,\n      \"oldestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestReadStartedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"readStartSkewMs\": 0,\n      \"oldestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"newestPublishedAt\": \"2026-05-10T10:00:00.000Z\",\n      \"oldestReadStartAgeMs\": 0\n    },\n    \"filters\": {},\n    \"pagination\": {\n      \"page\": 1,\n      \"pageSize\": 100,\n      \"returned\": 0,\n      \"totalRows\": 0,\n      \"hasMore\": false,\n      \"nextPage\": null\n    },\n    \"rowCount\": 0,\n    \"elapsedMs\": 1,\n    \"executedAt\": \"2026-05-10T10:00:00.000Z\"\n  }\n}"}],"_postman_id":"177c88b4-7a6c-4d32-b05e-5ac5b18ffb39"}],"id":"523cab16-7b30-42a7-8c27-f79ec481b08d","description":"<p>Snapshot reads of the reports in the live family <em>Customer discounts</em> (1); each request names its live equivalent.</p>\n<ul>\n<li><strong>Customer product-group discounts</strong> — <code>GET /v1/snapshot/{companyCode}/{financialYear}/customers/{customerId}/product-group-discounts</code></li>\n</ul>\n","_postman_id":"523cab16-7b30-42a7-8c27-f79ec481b08d","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}}],"id":"7ed65a62-ab0a-4c60-a409-acf93b3e3af5","description":"<blockquote>\n<p><strong>Availability.</strong> These GET routes read server-side SQLite snapshots without contacting the PC. A request still needs a valid cloud token and readable published data. A 401 confirms only that authentication is required; it does not prove a data response. A missing company-year or required table has its documented 404, while an unreadable snapshot returns <code>503 SNAPSHOT_UNREADABLE</code>.</p>\n</blockquote>\n<p>Snapshot routes answer from the latest available snapshot of each BUSY table of the organization (a newly available\nversion is used once a short settling period has passed, 2 minutes by default), not from the live PC, which may be\noffline; every answer reports how recent its data is (<code>metadata.snapshot</code>). They take the same\n<code>Authorization: Bearer &lt;organization API token&gt;</code>, the same subscription and feature gate, the same company scope\nand the same envelope as every public route, are <code>GET</code> only (another method on a known path is <code>405</code>), take scope\nfrom the path (<code>{companyCode}</code>, four-digit <code>{financialYear}</code>), refuse unknown or repeated query members with\n<code>400 INVALID_PARAMETER</code>, and answer <code>Cache-Control: private, no-store</code>. A snapshot stays readable whatever the\nPC's current configuration, the plan's company or year counts, or the data's age; only the token, its company scope\nand the subscription gate decide access.</p>\n<p><strong>Members every SQL snapshot operation accepts</strong> (all routes below except the first two):</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Member</th>\n<th>Type</th>\n<th>Rule</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>maxSkewMs</code></td>\n<td>integer</td>\n<td>milliseconds, 0 to 86400000. Refuse the answer (409 SNAPSHOT_SKEW_EXCEEDED, retryable) when the tables it reads were read on the PC further apart than this; 409 SNAPSHOT_FRESHNESS_UNKNOWN when a table has no recorded read time</td>\n<td>no bound</td>\n</tr>\n<tr>\n<td><code>setId</code></td>\n<td>string</td>\n<td>16 lower-case hexadecimal characters copied from metadata.snapshot.setId of an earlier answer. Pins a multi-page read to the same snapshot: if the data changed since, the answer is 409 SNAPSHOT_SET_CHANGED and you restart from page 1</td>\n<td>no pin</td>\n</tr>\n<tr>\n<td><code>source</code></td>\n<td>string</td>\n<td>reserved; the only accepted value is snapshot</td>\n<td>snapshot</td>\n</tr>\n</tbody>\n</table>\n</div><p><strong>The 22 BUSY tables</strong> a company-year snapshot can contain (<code>GET /v1/snapshot/{companyCode}/{financialYear}</code> shows which are present): <code>Master1</code>, <code>MasterAddressInfo</code>, <code>MasterSupport</code>, <code>Folio1</code>, <code>Config</code>, <code>CheckList</code>, <code>BillingDet</code>, <code>Tran1</code>, <code>Tran2</code>, <code>Tran3</code>, <code>Tran4</code>, <code>Tran10</code>, <code>VchGSTSumItemWise</code>, <code>VchOtherInfo</code>, <code>Company</code>, <code>BusyUserLog</code>, <code>PrinterReps</code>, <code>ItemSerialNo</code>, <code>ItemDesc</code>, <code>OrgSalePurc</code>, <code>ItemParamDet</code>, <code>Help1</code>. Each operation needs some of them; when one is not available the answer is <code>404 SNAPSHOT_TABLE_MISSING</code> with <code>details.table</code>.</p>\n<p><strong>Paging</strong> (operations marked paged): <code>page</code> ≥ 1 (default 1) and <code>pageSize</code> 1–500 (default 100);\n<code>metadata.pagination</code> = <code>{ page, pageSize, returned, totalRows, hasMore, nextPage }</code> with an exact <code>totalRows</code>. Every\nsummary or total is computed over the whole range, never over the returned page.</p>\n","_postman_id":"7ed65a62-ab0a-4c60-a409-acf93b3e3af5","auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]},"isInherited":true,"source":{"_postman_id":"2c5e6107-2257-4357-9a20-49803c3534c5","id":"2c5e6107-2257-4357-9a20-49803c3534c5","name":"AI Zeny API (Local + Cloud)","type":"collection"}}}],"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"{{localApiToken}}"}]}},"variable":[{"key":"messageChannel","value":"email"}]}